Antidot_Antidot - Version 1.1.1

Version Notes

Fix facet with ampersand configuration for search engine > facets
Replace "-" with "&afs:feed" to separate feeds in url (compatibility with AFS 7.7)
Fix empty facet id sent when performing an empty query to afs to get facets list
Add description node for variants
Add cdata for variant name
Prevent to export empty categories node
Add cdata for variant name
Add variant details for grouped products

Download this release

Release Info

Developer Antidot
Extension Antidot_Antidot
Version 1.1.1
Comparing to
See all releases


Code changes from version 1.1.0 to 1.1.1

Files changed (86) hide show
  1. app/code/community/MDN/Antidot/Block/Catalogsearch/Result.php +1 -1
  2. app/code/community/MDN/Antidot/Block/System/Config/Button/AfsStore.php +2 -3
  3. app/code/community/MDN/Antidot/Helper/Data.php +45 -0
  4. app/code/community/MDN/Antidot/Model/Catalogsearch/Layer.php +1 -1
  5. app/code/community/MDN/Antidot/Model/Export/Product.php +54 -28
  6. app/code/community/MDN/Antidot/Model/Search/Suggest.php +21 -17
  7. app/code/community/MDN/Antidot/Model/System/Config/Facet.php +5 -1
  8. app/code/community/MDN/Antidot/Model/System/Config/Sort.php +4 -4
  9. app/code/community/MDN/Antidot/Test/Helper/CatalogSearch/Data.php +35 -0
  10. app/code/community/MDN/Antidot/Test/Helper/Data.php +28 -0
  11. app/code/community/MDN/Antidot/Test/Helper/Data/providers/testTranslateFacetlabel.yaml +16 -0
  12. app/code/community/MDN/Antidot/Test/Model/Export/Product.php +84 -0
  13. app/code/community/MDN/Antidot/Test/Model/Export/Product/fixtures/testWritePricesFixedtax.yaml +90 -0
  14. app/code/community/MDN/Antidot/Test/Model/Export/Product/fixtures/testWriteProductNoVariant.yaml +84 -0
  15. app/code/community/MDN/Antidot/Test/Model/Search/Suggest.php +40 -0
  16. app/code/community/MDN/Antidot/Test/Model/Search/Suggest/fixtures/testSuggest.yaml +35 -0
  17. app/code/community/MDN/Antidot/controllers/Front/SearchController.php +1 -1
  18. app/code/community/MDN/Antidot/etc/config.xml +24 -3
  19. app/locale/de_AT/MDN_Antidot.csv +1 -0
  20. app/locale/de_CH/MDN_Antidot.csv +1 -0
  21. app/locale/de_DE/MDN_Antidot.csv +1 -0
  22. lib/antidot/.gitignore +2 -0
  23. lib/antidot/.travis.yml +14 -0
  24. lib/antidot/AFS/ACP/afs_acp_connector.php +10 -0
  25. lib/antidot/AFS/SEARCH/FILTER/afs_filter.php +1 -0
  26. lib/antidot/AFS/SEARCH/FILTER/afs_native_function_filter.php +30 -0
  27. lib/antidot/AFS/SEARCH/TEST/clientDataHelperTest.php +176 -1
  28. lib/antidot/AFS/SEARCH/TEST/facetHelperTest.php +88 -0
  29. lib/antidot/AFS/SEARCH/TEST/facetTest.php +21 -0
  30. lib/antidot/AFS/SEARCH/TEST/headerHelperTest.php +691 -70
  31. lib/antidot/AFS/SEARCH/TEST/pagerHelperTest.php +27 -27
  32. lib/antidot/AFS/SEARCH/TEST/promoteBannerReplyHelper.php +101 -0
  33. lib/antidot/AFS/SEARCH/TEST/promoteRedirectReplyHelper.php +59 -0
  34. lib/antidot/AFS/SEARCH/TEST/promoteReplysetHelperTest.php +5 -2
  35. lib/antidot/AFS/SEARCH/TEST/queryCoderTest.php +9 -0
  36. lib/antidot/AFS/SEARCH/TEST/queryTest.php +245 -0
  37. lib/antidot/AFS/SEARCH/TEST/replyHelperTest.php +207 -0
  38. lib/antidot/AFS/SEARCH/TEST/replysetHelperTest.php +4 -4
  39. lib/antidot/AFS/SEARCH/TEST/responseHelperTest.php +1 -0
  40. lib/antidot/AFS/SEARCH/TEST/searchQueryManagerTest.php +35 -0
  41. lib/antidot/AFS/SEARCH/TEST/searchTest.php +47 -0
  42. lib/antidot/AFS/SEARCH/afs_base_reply_helper.php +0 -1
  43. lib/antidot/AFS/SEARCH/afs_client_data_helper.php +317 -36
  44. lib/antidot/AFS/SEARCH/afs_cluster_parameter.php +26 -0
  45. lib/antidot/AFS/SEARCH/afs_facet.php +46 -2
  46. lib/antidot/AFS/SEARCH/afs_facet_helper.php +82 -27
  47. lib/antidot/AFS/SEARCH/afs_facet_manager.php +33 -2
  48. lib/antidot/AFS/SEARCH/afs_facet_mode.php +33 -1
  49. lib/antidot/AFS/SEARCH/afs_feed_coder.php +4 -0
  50. lib/antidot/AFS/SEARCH/afs_filter_coder.php +4 -0
  51. lib/antidot/AFS/SEARCH/afs_filter_parameter.php +24 -0
  52. lib/antidot/AFS/SEARCH/afs_fts_mode.php +18 -0
  53. lib/antidot/AFS/SEARCH/afs_pager_helper.php +5 -3
  54. lib/antidot/AFS/SEARCH/afs_promote_banner_reply_helper.php +43 -0
  55. lib/antidot/AFS/SEARCH/afs_promote_redirect_reply_helper.php +34 -0
  56. lib/antidot/AFS/SEARCH/afs_promote_reply_helper.php +28 -26
  57. lib/antidot/AFS/SEARCH/afs_query.php +518 -94
  58. lib/antidot/AFS/SEARCH/afs_query_coder.php +117 -92
  59. lib/antidot/AFS/SEARCH/afs_reply_helper.php +21 -0
  60. lib/antidot/AFS/SEARCH/afs_reply_helper_factory.php +29 -1
  61. lib/antidot/AFS/SEARCH/afs_replyset_helper.php +3 -2
  62. lib/antidot/AFS/SEARCH/afs_response_helper.php +28 -15
  63. lib/antidot/AFS/SEARCH/afs_search.php +19 -0
  64. lib/antidot/AFS/SEARCH/afs_search_query_manager.php +55 -13
  65. lib/antidot/AFS/SEARCH/afs_sort_coder.php +4 -0
  66. lib/antidot/AFS/SEARCH/afs_sort_parameter.php +25 -0
  67. lib/antidot/AFS/afs_connector.php +7 -4
  68. lib/antidot/AFS/afs_feed.php +309 -0
  69. lib/antidot/AFS/afs_multiple_values_parameter.php +71 -0
  70. lib/antidot/AFS/afs_query_base.php +196 -54
  71. lib/antidot/AFS/afs_query_parameter.php +27 -0
  72. lib/antidot/AFS/afs_single_value_parameter.php +45 -0
  73. lib/antidot/AIF/afs_document.php +25 -25
  74. lib/antidot/COMMON/afs_exception.php +11 -1
  75. lib/antidot/COMMON/afs_versions.php +1 -1
  76. lib/antidot/COMMON/lib/JsonPath/JsonPath.php +279 -0
  77. lib/antidot/COMMON/lib/JsonPath/JsonStore.php +223 -0
  78. lib/antidot/COMMON/php-SAI/.gitignore +10 -10
  79. lib/antidot/README.md +6 -0
  80. lib/antidot/afs_lib.doxygen +19 -1
  81. lib/antidot/afs_lib.php +1 -0
  82. lib/antidot/afs_version.php +2 -2
  83. lib/antidot/composer.json +8 -0
  84. lib/antidot/doc/data/raw_example.php +205 -214
  85. lib/antidot/rules.mk +3 -3
  86. package.xml +4 -4
app/code/community/MDN/Antidot/Block/Catalogsearch/Result.php CHANGED
@@ -74,7 +74,7 @@ class MDN_Antidot_Block_CatalogSearch_Result extends Mage_CatalogSearch_Block_Re
74
  $availableOrders = array();
75
  foreach($availableSortable as $sort) {
76
  list($field, $label) = explode('|', $sort['sort']);
77
- $availableOrders[$field] = $label;
78
  }
79
 
80
  return $availableOrders;
74
  $availableOrders = array();
75
  foreach($availableSortable as $sort) {
76
  list($field, $label) = explode('|', $sort['sort']);
77
+ $availableOrders[$field] = Mage::helper('Antidot')->translateFacetlabel($label);
78
  }
79
 
80
  return $availableOrders;
app/code/community/MDN/Antidot/Block/System/Config/Button/AfsStore.php CHANGED
@@ -33,9 +33,8 @@ class MDN_Antidot_Block_System_Config_Button_AfsStore extends Mage_Adminhtml_Blo
33
  * we get the magento back-office session language to determine
34
  * the locale of the AfsStore Back-office link
35
  */
36
- $locale = Mage::getSingleton('adminhtml/session')->getLocale();
37
- $locArr = explode('_',$locale);
38
- $urlLocale = array_shift($locArr);
39
  if (in_array($urlLocale, $this->afsStoreLocales)) {
40
  $url .= $urlLocale;
41
  } else {
33
  * we get the magento back-office session language to determine
34
  * the locale of the AfsStore Back-office link
35
  */
36
+ $codeLocale = Mage::getSingleton('adminhtml/session')->getLocale();
37
+ $urlLocale = Mage::helper('Antidot')->getLanguageFromCodeLocale($codeLocale);
 
38
  if (in_array($urlLocale, $this->afsStoreLocales)) {
39
  $url .= $urlLocale;
40
  } else {
app/code/community/MDN/Antidot/Helper/Data.php CHANGED
@@ -203,6 +203,9 @@ class MDN_Antidot_Helper_Data extends Mage_Core_Helper_Abstract
203
  /**
204
  * Translate facet name
205
  *
 
 
 
206
  * @param $facetcode
207
  * @param $defaultValue
208
  * @return mixed
@@ -217,6 +220,48 @@ class MDN_Antidot_Helper_Data extends Mage_Core_Helper_Abstract
217
  return $label;
218
  }
219
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
220
  /**
221
  * Round a number
222
  *
203
  /**
204
  * Translate facet name
205
  *
206
+ * This one is used in FO, to display the facet name in the result page, it is based
207
+ * on the label returned by the previous search ws search call
208
+ *
209
  * @param $facetcode
210
  * @param $defaultValue
211
  * @return mixed
220
  return $label;
221
  }
222
 
223
+ /*
224
+ * MCNX-217 : Translate facet label on front office :
225
+ * - The facet labels stemming from hard-coded module sorting (Relevance, Name, etc...) are
226
+ * stored in English and translated by the magento module translation files
227
+ * - the facet labels stemming from the AFS WS facets, are stored in a serialized array
228
+ * contained all the translated labels, we change the one corresponding to the current language
229
+ *
230
+ * @param $label
231
+ * @return string
232
+ */
233
+ public function translateFacetlabel($label)
234
+ {
235
+ Mage::log($label, null, 'antidot.log');
236
+ if ($labels = @unserialize($label)) {
237
+ $magentoLocale = Mage::app()->getLocale()->getLocaleCode();
238
+ $antidotLanguage = $this->getLanguageFromCodeLocale($magentoLocale);
239
+ if (isset($labels[$antidotLanguage])) {
240
+ $label = $labels[$antidotLanguage];
241
+ } elseif (isset($labels[0])) {
242
+ $label = $labels[0];
243
+ } elseif (isset($labels['EN'])) {
244
+ $label = $labels['EN']; //default language
245
+ }
246
+ } else {
247
+ $label = Mage::helper('Antidot')->__($label);
248
+ }
249
+ return $label;
250
+ }
251
+
252
+ /*
253
+ * Get the language code (ex: en) from a locale code (ex: en_US)
254
+ *
255
+ * @param $codeLocale
256
+ * @return string
257
+ */
258
+ public function getLanguageFromCodeLocale($codeLocale)
259
+ {
260
+ $arr = explode('_', $codeLocale);
261
+ $antidotLanguage = array_shift($arr);
262
+ return $antidotLanguage;
263
+ }
264
+
265
  /**
266
  * Round a number
267
  *
app/code/community/MDN/Antidot/Model/Catalogsearch/Layer.php CHANGED
@@ -52,7 +52,7 @@ class MDN_Antidot_Model_Catalogsearch_Layer extends Mage_CatalogSearch_Model_Lay
52
  foreach($config as $facet) {
53
  list($id, $label) = explode('|', $facet['facet']);
54
  $key = sprintf('%02d', $facet['order']).'_'.$id; //sptrinf to ensure order : 10 is after 09
55
- $facets[$key] = array('id' => $id, 'label' => $label);
56
  }
57
  }
58
  ksort($facets);
52
  foreach($config as $facet) {
53
  list($id, $label) = explode('|', $facet['facet']);
54
  $key = sprintf('%02d', $facet['order']).'_'.$id; //sptrinf to ensure order : 10 is after 09
55
+ $facets[$key] = array('id' => $id, 'label' => Mage::helper('Antidot')->translateFacetlabel($label));
56
  }
57
  }
58
  ksort($facets);
app/code/community/MDN/Antidot/Model/Export/Product.php CHANGED
@@ -43,7 +43,7 @@ class MDN_Antidot_Model_Export_Product extends MDN_Antidot_Model_Export_Abstract
43
  protected $propertyLabel = array();
44
 
45
  protected $productsWithOperation = null;
46
-
47
  protected $productVisible = array(
48
  Mage_Catalog_Model_Product_Visibility::VISIBILITY_IN_SEARCH,
49
  Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH,
@@ -223,6 +223,35 @@ class MDN_Antidot_Model_Export_Product extends MDN_Antidot_Model_Export_Abstract
223
  if (count($stores) == 0)
224
  return;
225
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
226
  $this->xml->push('product', array('id' => $product->getId(), 'xml:lang' => $this->lang, 'autocomplete' => $this->autoCompleteProducts));
227
 
228
  $this->xml->push('websites');
@@ -259,7 +288,7 @@ class MDN_Antidot_Model_Export_Product extends MDN_Antidot_Model_Export_Abstract
259
  $this->writeGenders($product);
260
  $this->writeMisc($product);
261
 
262
- $this->writeVariants($product, $stores);
263
 
264
  $this->xml->pop();
265
  }
@@ -783,15 +812,28 @@ class MDN_Antidot_Model_Export_Product extends MDN_Antidot_Model_Export_Abstract
783
  */
784
  protected function writePrices($product, $parentProduct, $context, $store)
785
  {
 
 
 
 
 
 
 
 
 
 
 
 
 
786
  $prices = ($this->getPrices($parentProduct->getId(), $store->getWebsiteId()));
787
 
788
- $price = Mage::helper('tax')->getPrice($product, $prices['price'], true);
789
 
790
  //try to get price & pricecut
791
  if ($prices['final_price'] < $prices['price'])
792
  {
793
- $priceCut = Mage::helper('tax')->getPrice($product, $prices['price'], true);
794
- $price = Mage::helper('tax')->getPrice($product, $prices['final_price'], true);
795
  }
796
 
797
  $price = Mage::helper('directory')->currencyConvert($price, Mage::app()->getStore()->getCurrentCurrencyCode(), $store->getCurrentCurrencyCode());
@@ -987,12 +1029,13 @@ class MDN_Antidot_Model_Export_Product extends MDN_Antidot_Model_Export_Abstract
987
  }
988
 
989
  /**
990
- * Write variants produt
991
  *
992
  * @param Product $product
 
993
  * @param array $stores
994
  */
995
- protected function writeVariants($product, $stores)
996
  {
997
  $this->xml->push('variants');
998
 
@@ -1000,28 +1043,11 @@ class MDN_Antidot_Model_Export_Product extends MDN_Antidot_Model_Export_Abstract
1000
  $this->writeVariant($product, $product, $stores);
1001
  $this->xml->pop();
1002
 
1003
- $variantProducts = array();
1004
- switch($product->getTypeID())
1005
- {
1006
- case Mage_Catalog_Model_Product_Type::TYPE_CONFIGURABLE:
1007
- $variantProducts = $product->getTypeInstance(true)->getUsedProducts(null, $product);
1008
- break;
1009
- case Mage_Catalog_Model_Product_Type::TYPE_GROUPED:
1010
- $variantProducts = $product->getTypeInstance(true)->getAssociatedProducts($product);
1011
- break;
1012
- }
1013
-
1014
- if(count($variantProducts) > 0) {
1015
- foreach($variantProducts as $variantProduct) {
1016
 
1017
- //Do not include product if status is not enabled
1018
- if (!$variantProduct->getstatus() == 1)
1019
- continue;
1020
-
1021
- $this->xml->push('variant', array('id' => $variantProduct->getId()));
1022
- $this->writeVariant($variantProduct, $product, $stores);
1023
- $this->xml->pop();
1024
- }
1025
  }
1026
 
1027
  $this->xml->pop();
43
  protected $propertyLabel = array();
44
 
45
  protected $productsWithOperation = null;
46
+
47
  protected $productVisible = array(
48
  Mage_Catalog_Model_Product_Visibility::VISIBILITY_IN_SEARCH,
49
  Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH,
223
  if (count($stores) == 0)
224
  return;
225
 
226
+ /**
227
+ * MCNX-211 : check if grouped/configurables product has variant before begin export product
228
+ */
229
+ $variantProducts = array();
230
+ if ($product->getTypeID() == Mage_Catalog_Model_Product_Type::TYPE_CONFIGURABLE
231
+ || $product->getTypeID() == Mage_Catalog_Model_Product_Type::TYPE_GROUPED) {
232
+
233
+ switch ($product->getTypeID()) {
234
+ case Mage_Catalog_Model_Product_Type::TYPE_CONFIGURABLE:
235
+ $variantProductsColl = $product->getTypeInstance(true)->getUsedProducts(null, $product);
236
+ break;
237
+ case Mage_Catalog_Model_Product_Type::TYPE_GROUPED:
238
+ $variantProductsColl = $product->getTypeInstance(true)->getAssociatedProducts($product);
239
+ break;
240
+ }
241
+
242
+ foreach ($variantProductsColl as $variantProduct) {
243
+ //Do not include product if status is not enabled
244
+ if ($variantProduct->getStatus() == 1) {
245
+ $variantProducts[] = $variantProduct;
246
+ }
247
+ }
248
+
249
+ //skip product if it has no active variant, but is a "variant" type
250
+ if (count($variantProducts) == 0) {
251
+ return;
252
+ }
253
+ }
254
+
255
  $this->xml->push('product', array('id' => $product->getId(), 'xml:lang' => $this->lang, 'autocomplete' => $this->autoCompleteProducts));
256
 
257
  $this->xml->push('websites');
288
  $this->writeGenders($product);
289
  $this->writeMisc($product);
290
 
291
+ $this->writeVariants($product, $variantProducts, $stores);
292
 
293
  $this->xml->pop();
294
  }
812
  */
813
  protected function writePrices($product, $parentProduct, $context, $store)
814
  {
815
+
816
+ /**
817
+ * MCNX-222 : Add Fixed Taxs to prices
818
+ */
819
+ $weeHelper = Mage::helper('weee');
820
+ $weeeAmount = 0;
821
+ if ($weeHelper->isEnabled($store)) {
822
+ $address = Mage::getModel('customer/address');
823
+ $address->setCountryId(Mage::helper('core')->getDefaultCountry($store));
824
+ $address->setQuote(Mage::getSingleton('sales/quote'));
825
+ $weeeAmount = $weeHelper->getAmount($product, $address, $address, $store->getWebsiteId(), false);
826
+ }
827
+
828
  $prices = ($this->getPrices($parentProduct->getId(), $store->getWebsiteId()));
829
 
830
+ $price = Mage::helper('tax')->getPrice($product, $prices['price'] + $weeeAmount, true);
831
 
832
  //try to get price & pricecut
833
  if ($prices['final_price'] < $prices['price'])
834
  {
835
+ $priceCut = Mage::helper('tax')->getPrice($product, $prices['price'] + $weeeAmount, true);
836
+ $price = Mage::helper('tax')->getPrice($product, $prices['final_price'] + $weeeAmount, true);
837
  }
838
 
839
  $price = Mage::helper('directory')->currencyConvert($price, Mage::app()->getStore()->getCurrentCurrencyCode(), $store->getCurrentCurrencyCode());
1029
  }
1030
 
1031
  /**
1032
+ * Write variants product
1033
  *
1034
  * @param Product $product
1035
+ * @param array $variantProducts
1036
  * @param array $stores
1037
  */
1038
+ protected function writeVariants($product, $variantProducts, $stores)
1039
  {
1040
  $this->xml->push('variants');
1041
 
1043
  $this->writeVariant($product, $product, $stores);
1044
  $this->xml->pop();
1045
 
1046
+ foreach($variantProducts as $variantProduct) {
 
 
 
 
 
 
 
 
 
 
 
 
1047
 
1048
+ $this->xml->push('variant', array('id' => $variantProduct->getId()));
1049
+ $this->writeVariant($variantProduct, $product, $stores);
1050
+ $this->xml->pop();
 
 
 
 
 
1051
  }
1052
 
1053
  $this->xml->pop();
app/code/community/MDN/Antidot/Model/Search/Suggest.php CHANGED
@@ -90,7 +90,7 @@ class MDN_Antidot_Model_Search_Suggest extends MDN_Antidot_Model_Search_Abstract
90
  list($lang) = explode('_', Mage::getStoreConfig('general/locale/code', Mage::app()->getStore()->getId()));
91
  foreach($this->feed as $key => $feed) {
92
  //take the storeId for product feed, website for others
93
- $id = ($key == 'products') ? Mage::app()->getStore()->getWebsiteId() : Mage::app()->getStore()->getId();
94
  $this->feed[$key]['name'] = sprintf($feed['tpl'], $id, $lang);
95
  }
96
 
@@ -104,13 +104,15 @@ class MDN_Antidot_Model_Search_Suggest extends MDN_Antidot_Model_Search_Abstract
104
  protected function loadFacetAutocomplete()
105
  {
106
  $facets = @unserialize(Mage::getStoreConfig('antidot/fields_product/properties'));
107
- foreach($facets as $facet) {
108
- if($facet['autocomplete'] === '1') {
109
- $this->feed['property_'.$facet['value']] = array(
110
- 'tpl' => 'property_'.$facet['value'].'_%d_%s',
111
- 'number' => self::DEFAULT_REPLIES_NUMBER,
112
- 'order' => (count($this->feed)+1),
113
- );
 
 
114
  }
115
  }
116
  }
@@ -121,15 +123,17 @@ class MDN_Antidot_Model_Search_Suggest extends MDN_Antidot_Model_Search_Abstract
121
  */
122
  protected function loadAdditionalFeeds()
123
  {
124
- $additionalFeeds = @unserialize(Mage::getStoreConfig('antidot/suggest/additionnal_feed'));
125
- foreach($additionalFeeds as $feed) {
126
- $addFeed = $feed['value'];
127
- $this->feed[$addFeed] = array(
128
- 'tpl' => $addFeed,
129
- 'number' => self::DEFAULT_REPLIES_NUMBER,
130
- 'order' => (count($this->feed)+1),
131
- );
132
- }
 
 
133
  }
134
 
135
 
90
  list($lang) = explode('_', Mage::getStoreConfig('general/locale/code', Mage::app()->getStore()->getId()));
91
  foreach($this->feed as $key => $feed) {
92
  //take the storeId for product feed, website for others
93
+ $id = ($key == 'products') ? Mage::app()->getStore()->getId() : Mage::app()->getStore()->getWebsiteId();
94
  $this->feed[$key]['name'] = sprintf($feed['tpl'], $id, $lang);
95
  }
96
 
104
  protected function loadFacetAutocomplete()
105
  {
106
  $facets = @unserialize(Mage::getStoreConfig('antidot/fields_product/properties'));
107
+ if (is_array($facets)) {
108
+ foreach ($facets as $facet) {
109
+ if ($facet['autocomplete'] === '1') {
110
+ $this->feed['property_'.$facet['value']] = array(
111
+ 'tpl' => 'property_'.$facet['value'].'_%d_%s',
112
+ 'number' => self::DEFAULT_REPLIES_NUMBER,
113
+ 'order' => (count($this->feed) + 1),
114
+ );
115
+ }
116
  }
117
  }
118
  }
123
  */
124
  protected function loadAdditionalFeeds()
125
  {
126
+ $additionalFeeds = @unserialize(Mage::getStoreConfig('antidot/suggest/additionnal_feed'));
127
+ if (is_array($additionalFeeds)) {
128
+ foreach ($additionalFeeds as $feed) {
129
+ $addFeed = $feed['value'];
130
+ $this->feed[$addFeed] = array(
131
+ 'tpl' => $addFeed,
132
+ 'number' => self::DEFAULT_REPLIES_NUMBER,
133
+ 'order' => (count($this->feed) + 1),
134
+ );
135
+ }
136
+ }
137
  }
138
 
139
 
app/code/community/MDN/Antidot/Model/System/Config/Facet.php CHANGED
@@ -30,7 +30,11 @@ class MDN_Antidot_Model_System_Config_Facet
30
  $this->options = array();
31
  foreach($search->getFacets() as $facetId => $facet) {
32
  if($typeExclude === null || $facet->get_type() !== $typeExclude) {
33
- $this->options[] = array('value' => $facetId.'|'.$facet->label, 'label' => $facetId.' ('.$facet->get_type().')');
 
 
 
 
34
  }
35
  }
36
 
30
  $this->options = array();
31
  foreach($search->getFacets() as $facetId => $facet) {
32
  if($typeExclude === null || $facet->get_type() !== $typeExclude) {
33
+ /*
34
+ * MCNX-217 : we store all the labels returned by the afsstore WS in a serialized array
35
+ * it will be used in front office using the current language
36
+ */
37
+ $this->options[] = array('value' => $facetId.'|'.serialize($facet->get_labels()), 'label' => $facetId.' ('.$facet->get_type().')');
38
  }
39
  }
40
 
app/code/community/MDN/Antidot/Model/System/Config/Sort.php CHANGED
@@ -43,7 +43,7 @@ class MDN_Antidot_Model_System_Config_Sort
43
 
44
  foreach($this->marketingFields as $field => $label) {
45
  if(Mage::getStoreConfig('antidot/fields_product/'.$field) != '') {
46
- $options[] = array('value' => $field.'|'.$label, 'label' => $label);
47
  }
48
  }
49
 
@@ -64,9 +64,9 @@ class MDN_Antidot_Model_System_Config_Sort
64
  public function initMarketingFields()
65
  {
66
  $this->marketingFields = array(
67
- 'is_new' => Mage::helper('Antidot')->__('Is new'),
68
- 'is_best_sale' => Mage::helper('Antidot')->__('Is top sale'),
69
- 'is_featured' => Mage::helper('Antidot')->__('Is featured'),
70
  );
71
  }
72
 
43
 
44
  foreach($this->marketingFields as $field => $label) {
45
  if(Mage::getStoreConfig('antidot/fields_product/'.$field) != '') {
46
+ $options[] = array('value' => $field.'|'.$label, 'label' => Mage::helper('Antidot')->__($label));
47
  }
48
  }
49
 
64
  public function initMarketingFields()
65
  {
66
  $this->marketingFields = array(
67
+ 'is_new' => 'Is new',
68
+ 'is_best_sale' => 'Is top sale',
69
+ 'is_featured' => 'Is featured',
70
  );
71
  }
72
 
app/code/community/MDN/Antidot/Test/Helper/CatalogSearch/Data.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Magento
5
+ *
6
+ * NOTICE OF LICENSE
7
+ *
8
+ * This source file is subject to the Open Software License (OSL 3.0)
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @copyright Copyright (c) 2015 Antidot (http://www.antidot.net)
13
+ * @author : Antidot devmagento@antidot.net
14
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
15
+ */
16
+ class MDN_Antidot_Test_Helper_CatalogSearch_Data extends EcomDev_PHPUnit_Test_Case {
17
+
18
+
19
+ /**
20
+ * MCNX-210 : make get helper work with this "wrong" case : catalogSearch instead of catalgsearch
21
+ *
22
+ * @test
23
+ */
24
+ public function testCase() {
25
+
26
+ $helper = Mage::helper('catalogSearch');
27
+
28
+ $this->assertEquals(
29
+ 'MDN_Antidot_Helper_CatalogSearch_Data',
30
+ get_class($helper)
31
+ );
32
+
33
+ }
34
+
35
+ }
app/code/community/MDN/Antidot/Test/Helper/Data.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+
4
+ class MDN_Antidot_Test_Helper_Data extends EcomDev_PHPUnit_Test_Case
5
+ {
6
+
7
+ /**
8
+ * MCNX-217 : Test translation of facet fields
9
+ *
10
+ * @test
11
+ * @dataProvider dataProvider
12
+ */
13
+ public function testTranslateFacetlabel($label, $locale, $expected)
14
+ {
15
+
16
+ /** @var $helper MDN_Antidot_Helper_Data */
17
+ $helper = Mage::helper('Antidot');
18
+
19
+ Mage::app()->getLocale()->setLocale($locale);
20
+ $translatedLabel = $helper->translateFacetlabel($label);
21
+
22
+ $this->assertEquals(
23
+ $expected,
24
+ $translatedLabel
25
+ );
26
+
27
+ }
28
+ }
app/code/community/MDN/Antidot/Test/Helper/Data/providers/testTranslateFacetlabel.yaml ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ -
2
+ - Relevance
3
+ - en_US
4
+ - Relevance
5
+ -
6
+ - a:3:{s:2:"de";s:14:"Verfügbarkeit";s:2:"en";s:12:"Availability";s:2:"fr";s:14:"Disponibilité";}
7
+ - en_US
8
+ - Availability
9
+ -
10
+ - a:3:{s:2:"de";s:14:"Verfügbarkeit";s:2:"en";s:12:"Availability";s:2:"fr";s:14:"Disponibilité";}
11
+ - fr_FR
12
+ - Disponibilité
13
+ -
14
+ - a:3:{s:2:"de";s:14:"Verfügbarkeit";s:2:"en";s:12:"Availability";s:2:"fr";s:14:"Disponibilité";}
15
+ - de_DE
16
+ - Verfügbarkeit
app/code/community/MDN/Antidot/Test/Model/Export/Product.php CHANGED
@@ -371,6 +371,90 @@ class MDN_Antidot_Test_Model_Export_Product extends EcomDev_PHPUnit_Test_Case
371
 
372
  }
373
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
374
  /**
375
  *
376
  * @param $productId
371
 
372
  }
373
 
374
+ /**
375
+ * MCNX-221 : test variant product without variant is not exported
376
+ * @test
377
+ * @loadFixture
378
+ */
379
+ public function testWriteProductNoVariant() {
380
+
381
+ /* @var $export \MDN_Antidot_Model_Export_Product */
382
+ $export = Mage::getModel('Antidot/export_product');
383
+
384
+ //Load a grouped product on store french, this product has no associated product
385
+ $storeId = 3;
386
+ Mage::app()->setCurrentStore($storeId);
387
+ $product = $this->loadProduct(1, $storeId);
388
+
389
+ MDN_Antidot_Test_PHPUnitUtil::callPrivateMethod($export,'initXml', array('product'));
390
+ /* @var $export \MDN_Antidot_Helper_Xml_Writer */
391
+ $xmlWriter = MDN_Antidot_Test_PHPUnitUtil::getPrivateProperty($export, 'xml');
392
+ $xmlWriter->flush();
393
+
394
+ /*
395
+ * The writeProduct method is called with the "empty" grouped product
396
+ */
397
+ MDN_Antidot_Test_PHPUnitUtil::callPrivateMethod($export,'writeProduct', array($product, array(Mage::app()->getStore())));
398
+
399
+ $this->assertEquals('', $xmlWriter->getXml());
400
+
401
+
402
+ }
403
+
404
+ /**
405
+ * MCNX-222 : test Write prices : Fixed tax prices
406
+ * @test
407
+ * @loadFixture
408
+ */
409
+ public function testWritePricesFixedtax() {
410
+
411
+ /* @var $export \MDN_Antidot_Model_Export_Product */
412
+ $export = Mage::getModel('Antidot/export_product');
413
+
414
+ $storeId = 3;
415
+ $store = Mage::getModel('core/store')->load($storeId);
416
+ $product = $this->loadProduct(1, $storeId);
417
+ $context = array('currency'=>'EUR', 'country'=>'FR');
418
+
419
+ MDN_Antidot_Test_PHPUnitUtil::callPrivateMethod($export,'initXml', array('product'));
420
+ /* @var $export \MDN_Antidot_Helper_Xml_Writer */
421
+ $xmlWriter = MDN_Antidot_Test_PHPUnitUtil::getPrivateProperty($export, 'xml');
422
+ $xmlWriter->flush();
423
+
424
+ /*
425
+ * The writePrices is called without fixed tax price activated
426
+ * expected data also in dataProvider
427
+ */
428
+ MDN_Antidot_Test_PHPUnitUtil::callPrivateMethod($export,'writePrices', array($product, $product, $context, $store));
429
+
430
+ $expected='<prices><price currency="EUR" type="PRICE_FINAL" vat_included="true" country="FR">12.99</price></prices>';
431
+ $this->assertEquals($expected, $xmlWriter->getXml());
432
+ $xmlWriter->flush();
433
+
434
+ /*
435
+ * The writePrices is called witout fixed tax price activated
436
+ * expected data also in dataProvider
437
+ */
438
+ $mockHelper = $this->getHelperMock('weee', array('isEnabled', 'getAmount'));
439
+ $mockHelper->expects($this->any())
440
+ ->method('isEnabled')
441
+ ->will($this->returnValue(true)); //activate fixed tax in the mock helper
442
+ $mockHelper->expects($this->any())
443
+ ->method('getAmount')
444
+ ->will($this->returnValue(3)); //Set a fixed tax price of 3 EUR in the mock helper
445
+ $this->replaceByMock('helper', 'weee', $mockHelper);
446
+
447
+ /*
448
+ * The writePrices is called with fixed tax price activated
449
+ * expected data also in dataProvider
450
+ */
451
+ MDN_Antidot_Test_PHPUnitUtil::callPrivateMethod($export,'writePrices', array($product, $product, $context, $store));
452
+
453
+ $expected='<prices><price currency="EUR" type="PRICE_FINAL" vat_included="true" country="FR">15.99</price></prices>';
454
+ $this->assertEquals($expected, $xmlWriter->getXml());
455
+
456
+
457
+ }
458
  /**
459
  *
460
  * @param $productId
app/code/community/MDN/Antidot/Test/Model/Export/Product/fixtures/testWritePricesFixedtax.yaml ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ scope:
2
+ website: # Initialize websites
3
+ - website_id: 2
4
+ code: usa_website
5
+ name: USA Website
6
+ default_group_id: 2
7
+ - website_id: 3
8
+ code: french_website
9
+ name: French Website
10
+ default_group_id: 3
11
+ - website_id: 4
12
+ code: german_website
13
+ name: German Website
14
+ default_group_id: 4
15
+ group: # Initializes store groups
16
+ - group_id: 2
17
+ website_id: 2
18
+ name: USA Store Group
19
+ default_store_id: 2
20
+ root_category_id: 2 # Default Category
21
+ - group_id: 3
22
+ website_id: 3
23
+ name: French Store Group
24
+ default_store_id: 3
25
+ root_category_id: 2 # Default Category
26
+ - group_id: 4
27
+ website_id: 4
28
+ name: German Store Group
29
+ default_store_id: 4
30
+ root_category_id: 2 # Default Category
31
+ store: # Initializes store views
32
+ - store_id: 2
33
+ website_id: 2
34
+ group_id: 2
35
+ code: usa
36
+ name: USA Store
37
+ is_active: 1
38
+ - store_id: 3
39
+ website_id: 3
40
+ group_id: 3
41
+ code: france
42
+ name: France Store
43
+ is_active: 1
44
+ - store_id: 4
45
+ website_id: 4
46
+ group_id: 4
47
+ code: germany
48
+ name: Germany Store
49
+ is_active: 1
50
+ config:
51
+ default/antidot/fields_product/properties: a:2:{s:18:"_1426953698813_813";a:2:{s:5:"value";s:7:"authors";s:12:"autocomplete";s:1:"0";}s:18:"_1426953714346_346";a:2:{s:5:"value";s:6:"editor";s:12:"autocomplete";s:1:"0";}}
52
+ default/web/secure/base_url: http://www.mywebsite.com/
53
+ default/web/unsecure/base_url: http://www.mywebsite.com/
54
+ stores/usa/web/secure/base_url: http://www.mywebsite.com/
55
+ stores/france/web/secure/base_url: http://www.monsiteweb.fr/
56
+ stores/germany/web/secure/base_url: http://www.meinwebseite.de/
57
+ stores/usa/web/unsecure/base_url: http://www.mywebsite.com/
58
+ stores/france/web/unsecure/base_url: http://www.monsiteweb.fr/
59
+ stores/germany/web/unsecure/base_url: http://www.meinwebseite.de/
60
+ eav:
61
+ catalog_product:
62
+ - entity_id: 1
63
+ type_id: simple
64
+ attribute_set_id: 4 # Default
65
+ sku: book
66
+ name: Book
67
+ short_description: Book
68
+ description: Book
69
+ url_key: book
70
+ image: b/o/book.jpg
71
+ thumbnail: b/o/book_small.jpg
72
+ stock:
73
+ qty: 100.00
74
+ is_in_stock: 1
75
+ website_ids:
76
+ - usa_website
77
+ - french_website
78
+ - german_website
79
+ category_ids:
80
+ - 2 # Default Category
81
+ price: 12.99
82
+ tax_class_id: 2 # Taxable Goods
83
+ status: 1 # Enabled
84
+ visibility: 4 # Visible in Catalog & Search
85
+ /websites: # Set different prices per website
86
+ usa_website:
87
+ special_price: 9.99
88
+ german_website:
89
+ price: 9.99
90
+ special_price: 5.99
app/code/community/MDN/Antidot/Test/Model/Export/Product/fixtures/testWriteProductNoVariant.yaml ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ scope:
2
+ website: # Initialize websites
3
+ - website_id: 2
4
+ code: usa_website
5
+ name: USA Website
6
+ default_group_id: 2
7
+ - website_id: 3
8
+ code: french_website
9
+ name: French Website
10
+ default_group_id: 3
11
+ - website_id: 4
12
+ code: german_website
13
+ name: German Website
14
+ default_group_id: 4
15
+ group: # Initializes store groups
16
+ - group_id: 2
17
+ website_id: 2
18
+ name: USA Store Group
19
+ default_store_id: 2
20
+ root_category_id: 2 # Default Category
21
+ - group_id: 3
22
+ website_id: 3
23
+ name: French Store Group
24
+ default_store_id: 3
25
+ root_category_id: 2 # Default Category
26
+ - group_id: 4
27
+ website_id: 4
28
+ name: German Store Group
29
+ default_store_id: 4
30
+ root_category_id: 2 # Default Category
31
+ store: # Initializes store views
32
+ - store_id: 2
33
+ website_id: 2
34
+ group_id: 2
35
+ code: usa
36
+ name: USA Store
37
+ is_active: 1
38
+ - store_id: 3
39
+ website_id: 3
40
+ group_id: 3
41
+ code: france
42
+ name: France Store
43
+ is_active: 1
44
+ - store_id: 4
45
+ website_id: 4
46
+ group_id: 4
47
+ code: germany
48
+ name: Germany Store
49
+ is_active: 1
50
+ config:
51
+ default/antidot/fields_product/properties: a:2:{s:18:"_1426953698813_813";a:2:{s:5:"value";s:7:"authors";s:12:"autocomplete";s:1:"0";}s:18:"_1426953714346_346";a:2:{s:5:"value";s:6:"editor";s:12:"autocomplete";s:1:"0";}}
52
+ default/web/secure/base_url: http://www.mywebsite.com/
53
+ default/web/unsecure/base_url: http://www.mywebsite.com/
54
+ stores/usa/web/secure/base_url: http://www.mywebsite.com/
55
+ stores/france/web/secure/base_url: http://www.monsiteweb.fr/
56
+ stores/germany/web/secure/base_url: http://www.meinwebseite.de/
57
+ stores/usa/web/unsecure/base_url: http://www.mywebsite.com/
58
+ stores/france/web/unsecure/base_url: http://www.monsiteweb.fr/
59
+ stores/germany/web/unsecure/base_url: http://www.meinwebseite.de/
60
+ eav:
61
+ catalog_product:
62
+ - entity_id: 1
63
+ type_id: grouped
64
+ attribute_set_id: 4 # Default
65
+ sku: books
66
+ name: Books
67
+ short_description: Books
68
+ description: Books
69
+ url_key: books
70
+ image: b/o/books.jpg
71
+ thumbnail: b/o/books_small.jpg
72
+ stock:
73
+ qty: 0
74
+ is_in_stock: 0
75
+ website_ids:
76
+ - usa_website
77
+ - french_website
78
+ - german_website
79
+ category_ids:
80
+ - 2 # Default Category
81
+ price: 0
82
+ tax_class_id: 2 # Taxable Goods
83
+ status: 1 # Enabled
84
+ visibility: 4 # Visible in Catalog & Search
app/code/community/MDN/Antidot/Test/Model/Search/Suggest.php ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Magento
5
+ *
6
+ * NOTICE OF LICENSE
7
+ *
8
+ * This source file is subject to the Open Software License (OSL 3.0)
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @copyright Copyright (c) 2015 Antidot (http://www.antidot.net)
13
+ * @author : Antidot devmagento@antidot.net
14
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
15
+ */
16
+ class MDN_Antidot_Test_Model_Search_Suggest extends EcomDev_PHPUnit_Test_Case
17
+ {
18
+
19
+ /**
20
+ * MCNX-226 and MCNX-227 : inverted storeid and websiteid on acp ws url cause no results
21
+ *
22
+ * @test
23
+ * @loadFixture
24
+ */
25
+ public function testSuggest() {
26
+
27
+ Mage::app()->setCurrentStore(5);
28
+
29
+ /** @var $observer MDN_Antidot_Model_Search_Suggest */
30
+ $suggest = Mage::getModel('Antidot/search_suggest');
31
+
32
+ $feeds = MDN_Antidot_Test_PHPUnitUtil::callPrivateMethod($suggest, 'getFeeds', array('products'));
33
+
34
+ $this->assertEquals(
35
+ 'featured_products_5_fr&afs:feed=categories_3_fr&afs:feed=brands_3_fr&afs:feed=articles_3_fr&afs:feed=stores_3_fr',
36
+ $feeds
37
+ );
38
+
39
+ }
40
+ }
app/code/community/MDN/Antidot/Test/Model/Search/Suggest/fixtures/testSuggest.yaml ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ scope:
2
+ website: # Initialize websites
3
+ - website_id: 3
4
+ code: french_website
5
+ name: French Website
6
+ default_group_id: 3
7
+ group: # Initializes store groups
8
+ - group_id: 3
9
+ website_id: 3
10
+ name: French Store Group
11
+ default_store_id: 3
12
+ root_category_id: 2 # Default Category
13
+ - group_id: 5
14
+ website_id: 3
15
+ name: French Store Group Discount
16
+ default_store_id: 5
17
+ root_category_id: 2 # Default Category
18
+ store: # Initializes store views
19
+ - store_id: 3
20
+ website_id: 3
21
+ group_id: 3
22
+ code: france
23
+ name: France Store
24
+ is_active: 1
25
+ - store_id: 5
26
+ website_id: 3
27
+ group_id: 5
28
+ code: france_discount
29
+ name: France Store Discount
30
+ is_active: 1
31
+
32
+ config:
33
+ default/general/locale/code: zz
34
+ stores/france/general/locale/code: fr
35
+ stores/france_discount/general/locale/code: fr
app/code/community/MDN/Antidot/controllers/Front/SearchController.php CHANGED
@@ -30,6 +30,6 @@ class MDN_Antidot_Front_SearchController extends Mage_Core_Controller_Front_Acti
30
  $format = $formatParam;
31
  }
32
 
33
- $this->getResponse()->setBody(Mage::getModel('Antidot/Search_Suggest')->get($query, $format));
34
  }
35
  }
30
  $format = $formatParam;
31
  }
32
 
33
+ $this->getResponse()->setBody(Mage::getModel('Antidot/search_suggest')->get($query, $format));
34
  }
35
  }
app/code/community/MDN/Antidot/etc/config.xml CHANGED
@@ -18,7 +18,7 @@
18
  </crontab>
19
  <modules>
20
  <MDN_Antidot>
21
- <version>1.1.0</version>
22
  </MDN_Antidot>
23
  </modules>
24
  <global>
@@ -31,6 +31,12 @@
31
  <data>MDN_Antidot_Helper_CatalogSearch_Data</data>
32
  </rewrite>
33
  </catalogsearch>
 
 
 
 
 
 
34
  <enterprise_search>
35
  <rewrite>
36
  <data>MDN_Antidot_Helper_Enterprise_Search_Data</data>
@@ -129,6 +135,16 @@
129
  </adminhtml>
130
 
131
  <frontend>
 
 
 
 
 
 
 
 
 
 
132
  <routers>
133
  <Antidot>
134
  <use>standard</use>
@@ -192,7 +208,7 @@
192
  <xsl:variable name="categories-title">Categories</xsl:variable>
193
  <xsl:variable name="brands-title">Brands</xsl:variable>
194
  <!-- Thumbnail settings -->
195
- <xsl:variable name="thumbnail_width">35</xsl:variable>
196
  <!-- Price settings -->
197
  <xsl:variable name="display_price" select="true()"/>
198
  <xsl:variable name="decimal-separator">,</xsl:variable>
@@ -390,8 +406,13 @@
390
  <xsl:attribute name="class">image</xsl:attribute>
391
  <xsl:attribute name="style">float: left; margin-right:5px;</xsl:attribute>
392
  <xsl:element name="img">
393
- <xsl:attribute name="width">
 
 
 
 
394
  <xsl:value-of select="$thumbnail_width"/>
 
395
  </xsl:attribute>
396
  <xsl:attribute name="src">
397
  <xsl:apply-templates select="@value"/>
18
  </crontab>
19
  <modules>
20
  <MDN_Antidot>
21
+ <version>1.1.1</version>
22
  </MDN_Antidot>
23
  </modules>
24
  <global>
31
  <data>MDN_Antidot_Helper_CatalogSearch_Data</data>
32
  </rewrite>
33
  </catalogsearch>
34
+ <!-- MCNX mcnx-210 : compatibility case : catalagSearch (solutionlevage), we duplicate the rewrite definition for this "special" case -->
35
+ <catalogSearch>
36
+ <rewrite>
37
+ <data>MDN_Antidot_Helper_CatalogSearch_Data</data>
38
+ </rewrite>
39
+ </catalogSearch>
40
  <enterprise_search>
41
  <rewrite>
42
  <data>MDN_Antidot_Helper_Enterprise_Search_Data</data>
135
  </adminhtml>
136
 
137
  <frontend>
138
+ <!-- Antidot module translation are needed in front for the sort labels -->
139
+ <translate>
140
+ <modules>
141
+ <MDN_Antidot>
142
+ <files>
143
+ <default>MDN_Antidot.csv</default>
144
+ </files>
145
+ </MDN_Antidot>
146
+ </modules>
147
+ </translate>
148
  <routers>
149
  <Antidot>
150
  <use>standard</use>
208
  <xsl:variable name="categories-title">Categories</xsl:variable>
209
  <xsl:variable name="brands-title">Brands</xsl:variable>
210
  <!-- Thumbnail settings -->
211
+ <xsl:variable name="thumbnail_width">40</xsl:variable>
212
  <!-- Price settings -->
213
  <xsl:variable name="display_price" select="true()"/>
214
  <xsl:variable name="decimal-separator">,</xsl:variable>
406
  <xsl:attribute name="class">image</xsl:attribute>
407
  <xsl:attribute name="style">float: left; margin-right:5px;</xsl:attribute>
408
  <xsl:element name="img">
409
+ <xsl:attribute name="style">
410
+ <xsl:text>max-width:</xsl:text>
411
+ <xsl:value-of select="$thumbnail_width"/>
412
+ <xsl:text>px;</xsl:text>
413
+ <xsl:text>max-height:</xsl:text>
414
  <xsl:value-of select="$thumbnail_width"/>
415
+ <xsl:text>px;</xsl:text>
416
  </xsl:attribute>
417
  <xsl:attribute name="src">
418
  <xsl:apply-templates select="@value"/>
app/locale/de_AT/MDN_Antidot.csv CHANGED
@@ -127,6 +127,7 @@ Relevance,Relevanz
127
  Position,Position
128
  Name,Name
129
  Price,Preis
 
130
  "Is promotional",Förgerung
131
  "Is new",Neuigkeiten
132
  "Is top sale",Spitzenverkaufs
127
  Position,Position
128
  Name,Name
129
  Price,Preis
130
+ "Stock","Lager"
131
  "Is promotional",Förgerung
132
  "Is new",Neuigkeiten
133
  "Is top sale",Spitzenverkaufs
app/locale/de_CH/MDN_Antidot.csv CHANGED
@@ -127,6 +127,7 @@ Relevance,Relevanz
127
  Position,Position
128
  Name,Name
129
  Price,Preis
 
130
  "Is promotional",Förgerung
131
  "Is new",Neuigkeiten
132
  "Is top sale",Spitzenverkaufs
127
  Position,Position
128
  Name,Name
129
  Price,Preis
130
+ "Stock","Lager"
131
  "Is promotional",Förgerung
132
  "Is new",Neuigkeiten
133
  "Is top sale",Spitzenverkaufs
app/locale/de_DE/MDN_Antidot.csv CHANGED
@@ -127,6 +127,7 @@ Relevance,Relevanz
127
  Position,Position
128
  Name,Name
129
  Price,Preis
 
130
  "Is promotional",Förgerung
131
  "Is new",Neuigkeiten
132
  "Is top sale",Spitzenverkaufs
127
  Position,Position
128
  Name,Name
129
  Price,Preis
130
+ "Stock","Lager"
131
  "Is promotional",Förgerung
132
  "Is new",Neuigkeiten
133
  "Is top sale",Spitzenverkaufs
lib/antidot/.gitignore CHANGED
@@ -3,3 +3,5 @@ doc/html
3
  *.bak
4
  *.swp
5
  *#*
 
 
3
  *.bak
4
  *.swp
5
  *#*
6
+ .idea
7
+ coverage
lib/antidot/.travis.yml ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ language: php
2
+
3
+ php:
4
+ - 5.5
5
+ - 5.4
6
+ - 5.3
7
+
8
+ before_install:
9
+ - sudo apt-get update > /dev/null
10
+
11
+ install:
12
+ - sudo apt-get install -y --force-yes make
13
+
14
+ script: make
lib/antidot/AFS/ACP/afs_acp_connector.php CHANGED
@@ -37,4 +37,14 @@ class AfsAcpConnector extends AfsConnector
37
  {
38
  return array('error' => $message, 'details' => $details);
39
  }
 
 
 
 
 
 
 
 
 
 
40
  }
37
  {
38
  return array('error' => $message, 'details' => $details);
39
  }
40
+
41
+ /** @internal
42
+ * @brief Overloads default implementation by setting json version to 1 in order to make it work with the API.
43
+ * @param $parameters [in-out] List of parameters to update with standard parameters.
44
+ */
45
+ protected function update_with_defaults(array& $parameters)
46
+ {
47
+ parent::update_with_defaults($parameters);
48
+ $parameters['afs:output'] = 'json,1';
49
+ }
50
  }
lib/antidot/AFS/SEARCH/FILTER/afs_filter.php CHANGED
@@ -2,6 +2,7 @@
2
  /** @file afs_filter.php */
3
 
4
  require_once 'AFS/SEARCH/FILTER/afs_operator_filter.php';
 
5
 
6
  /** @brief Helper function to create new AfsFilter instance.
7
  * @param $id [in] Filter identifier.
2
  /** @file afs_filter.php */
3
 
4
  require_once 'AFS/SEARCH/FILTER/afs_operator_filter.php';
5
+ require_once 'AFS/SEARCH/FILTER/afs_native_function_filter.php';
6
 
7
  /** @brief Helper function to create new AfsFilter instance.
8
  * @param $id [in] Filter identifier.
lib/antidot/AFS/SEARCH/FILTER/afs_native_function_filter.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Created by PhpStorm.
4
+ * User: ct
5
+ * Date: 11/4/14
6
+ * Time: 8:21 AM
7
+ */
8
+
9
+ function native_function_filter($function_name, $function_params) {
10
+ return new AfsFilterWrapper(null, new AfsNativeFunctionFilter($function_name, $function_params));
11
+ }
12
+
13
+ class AfsNativeFunctionFilter extends AfsFilter {
14
+ private $function_name = null;
15
+ private $function_params = array();
16
+
17
+ public function __construct($function_name, $function_params) {
18
+ $this->function_name = $function_name;
19
+ $this->function_params = $function_params;
20
+ }
21
+
22
+ public function to_string() {
23
+ return $this->function_name . '(' . implode(',', $this->function_params) . ')';
24
+ }
25
+ }
26
+
27
+ abstract class AfsNativeFunction {
28
+
29
+ const Geo_dist = "geo:dist";
30
+ }
lib/antidot/AFS/SEARCH/TEST/clientDataHelperTest.php CHANGED
@@ -168,7 +168,7 @@ class ClientDataHelperTest extends PHPUnit_Framework_TestCase
168
  $this->assertEquals($helper->mime_type, 'application/json');
169
  }
170
 
171
- public function testRetrieveSimpleJSONDataAsText()
172
  {
173
  $input = json_decode('{
174
  "clientData": [
@@ -302,4 +302,179 @@ class ClientDataHelperTest extends PHPUnit_Framework_TestCase
302
  $doc = new DOMDocument();
303
  $doc->loadXML($data);
304
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
305
  }
168
  $this->assertEquals($helper->mime_type, 'application/json');
169
  }
170
 
171
+ public function testRetrieveSimpleJSONDataAsText2()
172
  {
173
  $input = json_decode('{
174
  "clientData": [
302
  $doc = new DOMDocument();
303
  $doc->loadXML($data);
304
  }
305
+
306
+ public function testJsonCltDataGetValueJsonClientDataHelper() {
307
+ $input = json_decode('
308
+ {
309
+ "contents": { "data1": "value1",
310
+ "data2": [ { "k": "v" } ] },
311
+ "id": "id1",
312
+ "mimeType": "application/json"
313
+ }');
314
+
315
+
316
+ $json_clientdata = new AfsJsonClientDataHelper($input);
317
+ $this->assertEquals('value1', $json_clientdata->get_node("$.data1"));
318
+ $this->assertEquals('v', $json_clientdata->get_node("$.data2[0].k"));
319
+
320
+ $expected_result = array("data1" => "value1", "data2" => array(array("k" => "v")));
321
+ $this->assertEquals(array($expected_result),
322
+ $json_clientdata->get_nodes(""));
323
+ $this->assertEquals(array($expected_result),
324
+ $json_clientdata->get_nodes());
325
+ $this->assertEquals($expected_result,
326
+ $json_clientdata->get_node(""));
327
+ $this->assertEquals($expected_result,
328
+ $json_clientdata->get_node());
329
+ }
330
+
331
+ public function testJsonCltDataFirstElementReturnedByGetNode() {
332
+ $input = json_decode('
333
+ {
334
+ "contents": {
335
+ "data1": [ { "k": "v" } ], "data1": "value1" },
336
+ "id": "id1",
337
+ "mimeType": "application/json"
338
+ }');
339
+
340
+ $json_clientdata = new AfsJsonClientDataHelper($input);
341
+ $this->assertEquals('value1', $json_clientdata->get_node("$.data1"));
342
+ }
343
+
344
+ public function testJsonCltDataMultipleElementsReturnedByGetNodes() {
345
+ $input = json_decode('
346
+ {
347
+ "contents": { "data1": "value1",
348
+ "data": { "data1": [ { "k": "v" } ] }},
349
+ "id": "id1",
350
+ "mimeType": "application/json"
351
+ }');
352
+
353
+ $json_clientdata = new AfsJsonClientDataHelper($input);
354
+ $this->assertTrue(in_array('value1', $json_clientdata->get_nodes("$..data1")));
355
+ $this->assertTrue(in_array(array(array("k" => "v")), $json_clientdata->get_nodes("$..data1")));
356
+ }
357
+
358
+ /**
359
+ * @expectedException AfsNoResultException
360
+ */
361
+ public function testJsonCltDataNoElementFoundGetNode() {
362
+ $input = json_decode('
363
+ {
364
+ "contents": { "dataa1": "value1",
365
+ "dataa2": [ { "k": "v" } ] },
366
+ "id": "id1",
367
+ "mimeType": "application/json"
368
+ }');
369
+ $json_clientdata = new AfsJsonClientDataHelper($input);
370
+ $json_clientdata->get_node("$.data1");
371
+ }
372
+
373
+ /**
374
+ * @expectedException AfsNoResultException
375
+ */
376
+ public function testJsonCltDataNoElementFoundgetNodes() {
377
+ $input = json_decode('
378
+ {
379
+ "contents": { "data1": "value1",
380
+ "data2": [ { "k": "v" } ] },
381
+ "id": "id1",
382
+ "mimeType": "application/json"
383
+ }');
384
+
385
+ $input = json_decode('
386
+ {
387
+ "contents": { "dataa1": "value1",
388
+ "dataa2": [ { "k": "v" } ] },
389
+ "id": "id1",
390
+ "mimeType": "application/json"
391
+ }');
392
+ $json_clientdata = new AfsJsonClientDataHelper($input);
393
+ $json_clientdata->get_nodes("$.data1");
394
+ }
395
+
396
+ public function testXmlCltDataGetNodeDataHelper() {
397
+ $xml_client_data = '<clientData><data1 attr=\"foo\">value1</data1><data2><data1>value2</data1></data2></clientData>';
398
+ $input = json_decode('
399
+ {
400
+ "contents": "' . $xml_client_data . '",
401
+ "id": "id1",
402
+ "mimeType": "application/json"
403
+ }');
404
+
405
+
406
+ $xml_clientdata = new AfsXmlClientDataHelper($input);
407
+ $this->assertEquals(array("data1" => array('attributes' => array( 'attr' => 'foo'), "value1")), $xml_clientdata->get_node("/clientData/data1"));
408
+ $this->assertEquals(array("data2" => array("data1" => "value2")), $xml_clientdata->get_node("/clientData/data2"));
409
+
410
+ $expected_result =array('clientData' => array("data1" => array('attributes' => array( 'attr' => 'foo'), "value1"), "data2" => array("data1" => "value2")));
411
+ $this->assertEquals(array($expected_result),
412
+ $xml_clientdata->get_nodes(""));
413
+ $this->assertEquals(array($expected_result),
414
+ $xml_clientdata->get_nodes());
415
+ $this->assertEquals($expected_result,
416
+ $xml_clientdata->get_node(""));
417
+ $this->assertEquals($expected_result,
418
+ $xml_clientdata->get_node());
419
+ }
420
+
421
+ public function testXmlCltDataFirstElementReturnedByGetNode() {
422
+ $xml_client_data = '<clientData><data1>value1</data1><data1><k>v</k></data1></clientData>';
423
+ $input = json_decode('
424
+ {
425
+ "contents": "' . $xml_client_data . '",
426
+ "id": "id1",
427
+ "mimeType": "application/json"
428
+ }');
429
+
430
+ $xml_clientdata = new AfsXmlClientDataHelper($input);
431
+ $this->assertEquals(array('data1' => 'value1'), $xml_clientdata->get_node("/clientData/data1"));
432
+ }
433
+
434
+ public function testXmlCltDataMultipleElementsReturnedByGetNodes() {
435
+ $xml_client_data = '<clientData><data1 attr=\"bidule\">value1</data1><data1><k>v</k></data1></clientData>';
436
+ $input = json_decode('
437
+ {
438
+ "contents": "' . $xml_client_data . '",
439
+ "id": "id1",
440
+ "mimeType": "application/json"
441
+ }');
442
+
443
+ $xml_clientdata = new AfsXmlClientDataHelper($input);
444
+ $this->assertTrue(in_array(array('attr' => 'bidule'), $xml_clientdata->get_nodes("//data1/@attr")));
445
+ $this->assertTrue(in_array(array("data1" => array("attributes" => array('attr' => 'bidule'), "value1")), $xml_clientdata->get_nodes("//data1")));
446
+ $this->assertTrue(in_array(array("data1" => array("k" => "v")), $xml_clientdata->get_nodes("//data1")));
447
+ }
448
+
449
+ /**
450
+ * @expectedException AfsNoResultException
451
+ */
452
+ public function testXmlCltDataNoElementFoundGetNode() {
453
+ $xml_client_data = '<clientData><data1>value1</data1><data1><k>v</k></data1></clientData>';
454
+ $input = json_decode('
455
+ {
456
+ "contents": "' . $xml_client_data . '",
457
+ "id": "id1",
458
+ "mimeType": "application/json"
459
+ }');
460
+
461
+ $xml_clientdata = new AfsXmlClientDataHelper($input);
462
+ $xml_clientdata->get_node("/foo");
463
+ }
464
+
465
+ /**
466
+ * @expectedException AfsNoResultException
467
+ */
468
+ public function testXmlCltDataNoElementFoundgetNodes() {
469
+ $xml_client_data = '<clientData><data1>value1</data1><data1><k>v</k></data1></clientData>';
470
+ $input = json_decode('
471
+ {
472
+ "contents": "' . $xml_client_data . '",
473
+ "id": "id1",
474
+ "mimeType": "application/json"
475
+ }');
476
+
477
+ $xml_clientdata = new AfsXmlClientDataHelper($input);
478
+ $xml_clientdata->get_node("/foo");
479
+ }
480
  }
lib/antidot/AFS/SEARCH/TEST/facetHelperTest.php CHANGED
@@ -54,6 +54,94 @@ class FacetHelperTest extends PHPUnit_Framework_TestCase
54
  $this->assertEquals(AfsFacetType::BOOL_TYPE, $helper->get_type());
55
  $this->assertEquals(AfsFacetLayout::TREE, $helper->get_layout());
56
  $this->assertEquals(false, $helper->is_sticky());
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
  }
58
 
59
  public function testRetrieveStickyness()
54
  $this->assertEquals(AfsFacetType::BOOL_TYPE, $helper->get_type());
55
  $this->assertEquals(AfsFacetLayout::TREE, $helper->get_layout());
56
  $this->assertEquals(false, $helper->is_sticky());
57
+
58
+ $labels = $helper->get_labels();
59
+ $this->assertEquals(array("ES" => "Faceta booleana", "FR" => "Facette booléenne", "Boolean facet"), $labels);
60
+ }
61
+
62
+ public function testRetrieveLabelsWhenNoLabelsExists() {
63
+ $input = json_decode('{
64
+ "afs:t": "FacetTree",
65
+ "node": [
66
+ {
67
+ "key": "false",
68
+ "labels": [
69
+ {
70
+ "label": "BAD"
71
+ }
72
+ ],
73
+ "items": 67
74
+ }
75
+ ],
76
+ "layout": "TREE",
77
+ "type": "BOOL",
78
+ "id": "FOO",
79
+ "sticky": "true" }');
80
+
81
+ $config = new AfsHelperConfiguration();
82
+ $helper = new AfsFacetHelper($input, new AfsQuery(), $config);
83
+ $labels = $helper->get_labels();
84
+ $this->assertEquals(array("FOO"), $labels);
85
+ $this->assertEquals("FOO", $helper->get_label());
86
+ }
87
+
88
+ public function testRetrieveTags() {
89
+ $input = json_decode('{
90
+ "afs:t": "FacetTree",
91
+ "tags": "tag1 tag2 tag3",
92
+ "node": [
93
+ {
94
+ "key": "false",
95
+ "labels": [
96
+ {
97
+ "label": "BAD"
98
+ }
99
+ ],
100
+ "items": 67
101
+ }
102
+ ],
103
+ "layout": "TREE",
104
+ "type": "BOOL",
105
+ "id": "FOO",
106
+ "labels": [
107
+ {
108
+ "label": "String facet"
109
+ }
110
+ ],
111
+ "sticky": "true" }');
112
+
113
+ $config = new AfsHelperConfiguration();
114
+ $helper = new AfsFacetHelper($input, new AfsQuery(), $config);
115
+ $this->assertEquals(array('tag1', 'tag2', 'tag3'), $helper->get_tags());
116
+ }
117
+
118
+ public function testNotags() {
119
+ $input = json_decode('{
120
+ "afs:t": "FacetTree",
121
+ "node": [
122
+ {
123
+ "key": "false",
124
+ "labels": [
125
+ {
126
+ "label": "BAD"
127
+ }
128
+ ],
129
+ "items": 67
130
+ }
131
+ ],
132
+ "layout": "TREE",
133
+ "type": "BOOL",
134
+ "id": "FOO",
135
+ "labels": [
136
+ {
137
+ "label": "String facet"
138
+ }
139
+ ],
140
+ "sticky": "true" }');
141
+
142
+ $config = new AfsHelperConfiguration();
143
+ $helper = new AfsFacetHelper($input, new AfsQuery(), $config);
144
+ $this->assertEquals(array(), $helper->get_tags());
145
  }
146
 
147
  public function testRetrieveStickyness()
lib/antidot/AFS/SEARCH/TEST/facetTest.php CHANGED
@@ -15,6 +15,27 @@ class FacetTest extends PHPUnit_Framework_TestCase
15
  $this->assertFalse($facet->has_single_mode());
16
  }
17
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  public function testFailOnBadTypeValue()
19
  {
20
  try {
15
  $this->assertFalse($facet->has_single_mode());
16
  }
17
 
18
+ public function testFailOnBadIdentifier()
19
+ {
20
+ try {
21
+ $facet = new AfsFacet(NULL);
22
+ $this->fail('Should have failed on invalid identifier');
23
+ } catch (InvalidArgumentException $e) { }
24
+ try {
25
+ $facet = new AfsFacet('');
26
+ $this->fail('Should have failed on invalid identifier');
27
+ } catch (InvalidArgumentException $e) { }
28
+ try {
29
+ $facet = new AfsFacet('4foo');
30
+ $this->fail('Should have failed on invalid identifier');
31
+ } catch (InvalidArgumentException $e) { }
32
+ try {
33
+ $facet = new AfsFacet('foo bar');
34
+ $this->fail('Should have failed on invalid identifier');
35
+ } catch (InvalidArgumentException $e) { }
36
+
37
+ }
38
+
39
  public function testFailOnBadTypeValue()
40
  {
41
  try {
lib/antidot/AFS/SEARCH/TEST/headerHelperTest.php CHANGED
@@ -1,81 +1,702 @@
1
  <?php ob_start();
2
- require_once "AFS/SEARCH/afs_header_helper.php";
 
 
3
 
4
- class HeaderHelperTest extends PHPUnit_Framework_TestCase
5
  {
6
- public function testError()
7
  {
8
  $input = json_decode('{
9
- "header": {
10
- "query": {
11
- "userId": "?",
12
- "sessionId": "?",
13
- "date": "2014-01-10T16:04:32+0000",
14
- "queryParam": [ ],
15
- "mainCtx": {
16
- "textQuery": ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  },
18
- "textQuery": ""
19
- },
20
- "user": {
21
- "requestMethod": "GET",
22
- "agent": "Mozilla/5.0 (X11; Linux x86_64; rv:24.0) Gecko/20100101 Firefox/24.0 Iceweasel/24.0",
23
- "address": "10.61.8.236",
24
- "output": {
25
- "format": "JSON",
26
- "encoding": "gzip",
27
- "charset": "UTF-8"
28
- }
29
- },
30
- "info": { },
31
- "error": {
32
- "message": [
33
- "errorMsg"
34
- ]
35
- }
36
- }
37
- }');
38
- $header = new AfsHeaderHelper($input->header);
39
- $this->assertTrue($header->in_error());
40
- $this->assertEquals('errorMsg', $header->get_error());
41
- }
42
-
43
- public function testNotInError()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  {
45
  $input = json_decode('{
46
- "header": {
47
- "query": {
48
- "userId": "e3eddaff-5a3d-4807-8fb2-09e13baf78e1",
49
- "sessionId": "4c0f28d1-bb67-469b-86bf-54f83432914e",
50
- "date": "2014-01-10T16:17:44+0000",
51
- "queryParam": [ ],
52
- "mainCtx": {
53
- "textQuery": ""
 
54
  },
55
- "textQuery": ""
56
- },
57
- "user": {
58
- "requestMethod": "GET",
59
- "agent": "Mozilla/5.0 (X11; Linux x86_64; rv:24.0) Gecko/20100101 Firefox/24.0 Iceweasel/24.0",
60
- "address": "10.61.8.236",
61
- "output": {
62
- "format": "JSON",
63
- "encoding": "gzip",
64
- "charset": "UTF-8"
65
- }
66
- },
67
- "performance": {
68
- "durationMs": 204
69
- },
70
- "info": { }
71
- }
72
- }');
73
- $header = new AfsHeaderHelper($input->header);
74
- $this->assertFalse($header->in_error());
75
- $this->assertEquals('e3eddaff-5a3d-4807-8fb2-09e13baf78e1', $header->get_user_id());
76
- $this->assertEquals('4c0f28d1-bb67-469b-86bf-54f83432914e', $header->get_session_id());
77
- $this->assertEquals(204, $header->get_duration());
78
- }
79
- }
80
 
 
 
 
81
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  <?php ob_start();
2
+ require_once "AFS/SEARCH/afs_facet_helper.php";
3
+ require_once "AFS/SEARCH/afs_query.php";
4
+ require_once "AFS/SEARCH/afs_response_helper.php";
5
 
6
+ class FacetHelperTest extends PHPUnit_Framework_TestCase
7
  {
8
+ public function testRetrieveFacetLabel()
9
  {
10
  $input = json_decode('{
11
+ "afs:t": "FacetTree",
12
+ "node": [
13
+ {
14
+ "key": "false",
15
+ "labels": [
16
+ {
17
+ "label": "BAD"
18
+ }
19
+ ],
20
+ "items": 67
21
+ },
22
+ {
23
+ "key": "true",
24
+ "labels": [
25
+ {
26
+ "label": "GOOD"
27
+ }
28
+ ],
29
+ "items": 133
30
+ }
31
+ ],
32
+ "layout": "TREE",
33
+ "type": "BOOL",
34
+ "id": "BOOL",
35
+ "labels": [
36
+ {
37
+ "lang": "ES",
38
+ "region": "ES",
39
+ "label": "Faceta booleana"
40
+ },
41
+ {
42
+ "lang": "FR",
43
+ "label": "Facette booléenne"
44
+ },
45
+ {
46
+ "label": "Boolean facet"
47
+ }
48
+ ] }');
49
+
50
+ $config = new AfsHelperConfiguration();
51
+ $helper = new AfsFacetHelper($input, new AfsQuery(), $config);
52
+ $this->assertEquals($helper->get_label(), "Faceta booleana");
53
+ $this->assertEquals('BOOL', $helper->get_id());
54
+ $this->assertEquals(AfsFacetType::BOOL_TYPE, $helper->get_type());
55
+ $this->assertEquals(AfsFacetLayout::TREE, $helper->get_layout());
56
+ $this->assertEquals(false, $helper->is_sticky());
57
+
58
+ $labels = $helper->get_labels();
59
+ $this->assertEquals(array("es" => "Faceta booleana", "fr" => "Facette booléenne", "Boolean facet"), $labels);
60
+ }
61
+
62
+ public function testRetrieveLabelsWhenNoLabelsExists() {
63
+ $input = json_decode('{
64
+ "afs:t": "FacetTree",
65
+ "node": [
66
+ {
67
+ "key": "false",
68
+ "labels": [
69
+ {
70
+ "label": "BAD"
71
+ }
72
+ ],
73
+ "items": 67
74
+ }
75
+ ],
76
+ "layout": "TREE",
77
+ "type": "BOOL",
78
+ "id": "FOO",
79
+ "sticky": "true" }');
80
+
81
+ $config = new AfsHelperConfiguration();
82
+ $helper = new AfsFacetHelper($input, new AfsQuery(), $config);
83
+ $labels = $helper->get_labels();
84
+ $this->assertEquals(array("FOO"), $labels);
85
+ $this->assertEquals("FOO", $helper->get_label());
86
+ }
87
+
88
+ public function testRetrieveTags() {
89
+ $input = json_decode('{
90
+ "afs:t": "FacetTree",
91
+ "tags": "tag1 tag2 tag3",
92
+ "node": [
93
+ {
94
+ "key": "false",
95
+ "labels": [
96
+ {
97
+ "label": "BAD"
98
+ }
99
+ ],
100
+ "items": 67
101
+ }
102
+ ],
103
+ "layout": "TREE",
104
+ "type": "BOOL",
105
+ "id": "FOO",
106
+ "labels": [
107
+ {
108
+ "label": "String facet"
109
+ }
110
+ ],
111
+ "sticky": "true" }');
112
+
113
+ $config = new AfsHelperConfiguration();
114
+ $helper = new AfsFacetHelper($input, new AfsQuery(), $config);
115
+ $this->assertEquals(array('tag1', 'tag2', 'tag3'), $helper->get_tags());
116
+ }
117
+
118
+ public function testNotags() {
119
+ $input = json_decode('{
120
+ "afs:t": "FacetTree",
121
+ "node": [
122
+ {
123
+ "key": "false",
124
+ "labels": [
125
+ {
126
+ "label": "BAD"
127
+ }
128
+ ],
129
+ "items": 67
130
+ }
131
+ ],
132
+ "layout": "TREE",
133
+ "type": "BOOL",
134
+ "id": "FOO",
135
+ "labels": [
136
+ {
137
+ "label": "String facet"
138
+ }
139
+ ],
140
+ "sticky": "true" }');
141
+
142
+ $config = new AfsHelperConfiguration();
143
+ $helper = new AfsFacetHelper($input, new AfsQuery(), $config);
144
+ $this->assertEquals(array(), $helper->get_tags());
145
+ }
146
+
147
+ public function testRetrieveStickyness()
148
+ {
149
+ $input = json_decode('{
150
+ "afs:t": "FacetTree",
151
+ "node": [
152
+ {
153
+ "key": "false",
154
+ "labels": [
155
+ {
156
+ "label": "BAD"
157
+ }
158
+ ],
159
+ "items": 67
160
+ }
161
+ ],
162
+ "layout": "TREE",
163
+ "type": "BOOL",
164
+ "id": "FOO",
165
+ "labels": [
166
+ {
167
+ "label": "String facet"
168
+ }
169
+ ],
170
+ "sticky": "true" }');
171
+
172
+ $config = new AfsHelperConfiguration();
173
+ $helper = new AfsFacetHelper($input, new AfsQuery(), $config);
174
+ $this->assertEquals($helper->get_label(), "String facet");
175
+ $this->assertEquals('FOO', $helper->get_id());
176
+ $this->assertEquals(AfsFacetType::BOOL_TYPE, $helper->get_type());
177
+ $this->assertEquals(AfsFacetLayout::TREE, $helper->get_layout());
178
+ $this->assertEquals(true, $helper->is_sticky());
179
+ }
180
+
181
+ public function testFacetValueNoMetaAvailable()
182
+ {
183
+ $input = json_decode('{
184
+ "afs:t": "FacetTree",
185
+ "node": [ {
186
+ "key": "false",
187
+ "labels": [ { "label": "BAD" } ],
188
+ "items": 67
189
+ } ],
190
+ "layout": "TREE",
191
+ "type": "BOOL",
192
+ "id": "BOOL",
193
+ "labels": [ { "label": "Boolean facet" } ] }');
194
+
195
+ $config = new AfsHelperConfiguration();
196
+ $config->set_helper_format(AfsHelperFormat::HELPERS);
197
+ $helper = new AfsFacetHelper($input, new AfsQuery(), $config);
198
+ $elems = $helper->get_elements();
199
+ $this->assertEquals(1, count($elems));
200
+ $this->assertEquals(0, count($elems[0]->get_meta()));
201
+ }
202
+
203
+ public function testFacetValueOneMetaAvailable()
204
+ {
205
+ $input = json_decode('{
206
+ "afs:t": "FacetTree",
207
+ "node": [ {
208
+ "key": "false",
209
+ "labels": [ { "label": "BAD" } ],
210
+ "items": 67,
211
+ "meta": [ {
212
+ "key": "meta_id",
213
+ "value": "meta_value"
214
+ } ]
215
+ } ],
216
+ "layout": "TREE",
217
+ "type": "BOOL",
218
+ "id": "BOOL",
219
+ "labels": [ { "label": "Boolean facet" } ]
220
+ }');
221
+
222
+ $config = new AfsHelperConfiguration();
223
+ $config->set_helper_format(AfsHelperFormat::HELPERS);
224
+ $helper = new AfsFacetHelper($input, new AfsQuery(), $config);
225
+ $elems = $helper->get_elements();
226
+
227
+ $this->assertEquals(1, count($elems));
228
+ $metas = $elems[0]->get_meta();
229
+ $this->assertEquals(1, count($metas));
230
+ foreach ($metas as $meta_key => $meta_value) {
231
+ $this->assertEquals('meta_id', $meta_key);
232
+ $this->assertEquals('meta_value', $meta_value);
233
+ }
234
+ $this->assertEquals('meta_value', $elems[0]->get_meta('meta_id'));
235
+ }
236
+
237
+ public function testFacetValueMultipleMetaAvailable()
238
+ {
239
+ $input = json_decode('{
240
+ "afs:t": "FacetTree",
241
+ "node": [ {
242
+ "key": "false",
243
+ "labels": [ { "label": "BAD" } ],
244
+ "items": 67,
245
+ "meta": [
246
+ {
247
+ "key": "meta_id_1",
248
+ "value": "meta_value_1"
249
  },
250
+ {
251
+ "key": "meta_id_2",
252
+ "value": "meta_value_2"
253
+ } ]
254
+ } ],
255
+ "layout": "TREE",
256
+ "type": "BOOL",
257
+ "id": "BOOL",
258
+ "labels": [ { "label": "Boolean facet" } ]
259
+ }');
260
+
261
+ $config = new AfsHelperConfiguration();
262
+ $config->set_helper_format(AfsHelperFormat::HELPERS);
263
+ $helper = new AfsFacetHelper($input, new AfsQuery(), $config);
264
+ $elems = $helper->get_elements();
265
+
266
+ $this->assertEquals(1, count($elems));
267
+ $metas = $elems[0]->get_meta();
268
+ $this->assertEquals(2, count($metas));
269
+ for ($i = 1; $i < 2; $i++) {
270
+ $res = each($metas);
271
+ $this->assertEquals('meta_id_' . $i, $res['key']);
272
+ $this->assertEquals('meta_value_' . $i, $res['value']);
273
+ }
274
+ $this->assertEquals('meta_value_1', $elems[0]->get_meta('meta_id_1'));
275
+ $this->assertEquals('meta_value_2', $elems[0]->get_meta('meta_id_2'));
276
+ }
277
+
278
+ public function testFacetValueWrongMetaRequested()
279
+ {
280
+ $input = json_decode('{
281
+ "afs:t": "FacetTree",
282
+ "node": [ {
283
+ "key": "false",
284
+ "labels": [ { "label": "BAD" } ],
285
+ "items": 67,
286
+ "meta": [
287
+ {
288
+ "key": "meta_id_1",
289
+ "value": "meta_value_1"
290
+ },
291
+ {
292
+ "key": "meta_id_2",
293
+ "value": "meta_value_2"
294
+ } ]
295
+ } ],
296
+ "layout": "TREE",
297
+ "type": "BOOL",
298
+ "id": "BOOL",
299
+ "labels": [ { "label": "Boolean facet" } ]
300
+ }');
301
+
302
+ $config = new AfsHelperConfiguration();
303
+ $config->set_helper_format(AfsHelperFormat::HELPERS);
304
+ $helper = new AfsFacetHelper($input, new AfsQuery(), $config);
305
+ $elems = $helper->get_elements();
306
+
307
+ $this->assertEquals(1, count($elems));
308
+ $metas = $elems[0]->get_meta();
309
+ $this->assertEquals(2, count($metas));
310
+ try {
311
+ $elems[0]->get_meta('unknown_meta_id');
312
+ $this->fail('Should have raised an exception on unknown meta id');
313
+ } catch (OutOfBoundsException $e) { }
314
+ }
315
+
316
+ public function testFacetValueMultipleMetaAvailableInArrayFormat()
317
  {
318
  $input = json_decode('{
319
+ "afs:t": "FacetTree",
320
+ "node": [ {
321
+ "key": "false",
322
+ "labels": [ { "label": "BAD" } ],
323
+ "items": 67,
324
+ "meta": [
325
+ {
326
+ "key": "meta_id_1",
327
+ "value": "meta_value_1"
328
  },
329
+ {
330
+ "key": "meta_id_2",
331
+ "value": "meta_value_2"
332
+ } ]
333
+ } ],
334
+ "layout": "TREE",
335
+ "type": "BOOL",
336
+ "id": "BOOL",
337
+ "labels": [ { "label": "Boolean facet" } ]
338
+ }');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
339
 
340
+ $config = new AfsHelperConfiguration();
341
+ $helper = new AfsFacetHelper($input, new AfsQuery(), $config);
342
+ $elems = $helper->get_elements();
343
 
344
+ $this->assertEquals(1, count($elems));
345
+ $metas = $elems[0]->meta;
346
+ $this->assertEquals(2, count($metas));
347
+ for ($i = 1; $i < 2; $i++) {
348
+ $res = each($metas);
349
+ $this->assertEquals('meta_id_' . $i, $res['key']);
350
+ $this->assertEquals('meta_value_' . $i, $res['value']);
351
+ }
352
+ }
353
+
354
+
355
+ public function testFacetElementBuilderOnInterval()
356
+ {
357
+ $input = json_decode('{
358
+ "afs:t": "FacetInterval",
359
+ "interval": [
360
+ {
361
+ "key": "[\"2009-10-02\" .. \"2013-10-01\"[",
362
+ "items": 109
363
+ },
364
+ {
365
+ "key": "[\"2010-10-02\" .. \"2013-10-01\"[",
366
+ "items": 97
367
+ }
368
+ ],
369
+ "layout": "INTERVAL",
370
+ "type": "DATE",
371
+ "id": "ADVANCED_INTERVAL_DATE",
372
+ "labels": [
373
+ {
374
+ "label": "Advanced date interval"
375
+ }
376
+ ]
377
+ }');
378
+
379
+ $query = new AfsQuery();
380
+ $config = new AfsHelperConfiguration();
381
+ $config->set_helper_format(AfsHelperFormat::HELPERS);
382
+ $facet_mgr = $query->get_facet_manager();
383
+ $facet_mgr->add_facet(new AfsFacet('ADVANCED_INTERVAL_DATE', AfsFacetType::DATE_TYPE, AfsFacetLayout::INTERVAL));
384
+ $builder = new AfsFacetElementBuilder($facet_mgr, $query);
385
+ $elems = $builder->create_elements('ADVANCED_INTERVAL_DATE', $input, $config);
386
+
387
+ $this->assertEquals(count($elems), 2);
388
+ $elem = reset($elems);
389
+ $this->assertEquals($elem->label, '["2009-10-02" .. "2013-10-01"[');
390
+ $this->assertEquals('["2009-10-02" .. "2013-10-01"[', $elem->key);
391
+ $this->assertEquals($elem->count, 109);
392
+ $this->assertFalse($elem->active);
393
+ $this->assertTrue($elem->query->has_filter('ADVANCED_INTERVAL_DATE', '["2009-10-02" .. "2013-10-01"['));
394
+ $this->assertEquals(count($elem->values), 0);
395
+ next($elems);
396
+ $elem = current($elems);
397
+ $this->assertEquals($elem->label, '["2010-10-02" .. "2013-10-01"[');
398
+ $this->assertEquals('["2010-10-02" .. "2013-10-01"[', $elem->key);
399
+ $this->assertEquals($elem->count, 97);
400
+ $this->assertFalse($elem->active);
401
+ $this->assertTrue($elem->query->has_filter('ADVANCED_INTERVAL_DATE', '["2010-10-02" .. "2013-10-01"['));
402
+ $this->assertEquals(count($elem->values), 0);
403
+ }
404
+
405
+ public function testFacetElementBuilderOnNode()
406
+ {
407
+ $input = json_decode('{
408
+ "afs:t": "FacetTree",
409
+ "node": [
410
+ {
411
+ "key": "false",
412
+ "labels": [
413
+ {
414
+ "label": "BAD"
415
+ }
416
+ ],
417
+ "items": 67
418
+ },
419
+ {
420
+ "key": "true",
421
+ "labels": [
422
+ {
423
+ "label": "GOOD"
424
+ }
425
+ ],
426
+ "items": 133
427
+ }
428
+ ],
429
+ "layout": "TREE",
430
+ "type": "BOOL",
431
+ "id": "BOOL",
432
+ "labels": [
433
+ {
434
+ "label": "Boolean facet"
435
+ }
436
+ ]
437
+ }');
438
+
439
+ $query = new AfsQuery();
440
+ $config = new AfsHelperConfiguration();
441
+ $config->set_helper_format(AfsHelperFormat::HELPERS);
442
+ $facet_mgr = $query->get_facet_manager();
443
+ $facet_mgr->add_facet(new AfsFacet('BOOL', AfsFacetType::BOOL_TYPE));
444
+ $builder = new AfsFacetElementBuilder($facet_mgr, $query);
445
+ $elems = $builder->create_elements('BOOL', $input, $config);
446
+
447
+ $this->assertEquals(count($elems), 2);
448
+ $elem = reset($elems);
449
+ $this->assertEquals($elem->label, 'BAD');
450
+ $this->assertEquals($elem->count, 67);
451
+ $this->assertFalse($elem->active);
452
+ $this->assertTrue($elem->query->has_filter('BOOL', 'false'));
453
+ $this->assertEquals(count($elem->values), 0);
454
+ next($elems);
455
+ $elem = current($elems);
456
+ $this->assertEquals($elem->label, 'GOOD');
457
+ $this->assertEquals($elem->count, 133);
458
+ $this->assertFalse($elem->active);
459
+ $this->assertTrue($elem->query->has_filter('BOOL', 'true'));
460
+ $this->assertEquals(count($elem->values), 0);
461
+ }
462
+
463
+ public function testFacetElementBuilderOnTreeNode()
464
+ {
465
+ $input = json_decode('{
466
+ "afs:t": "FacetTree",
467
+ "node": [
468
+ {
469
+ "key": "2010",
470
+ "labels": [
471
+ {
472
+ "lang": "FR",
473
+ "region": "FR",
474
+ "label": "2010"
475
+ }
476
+ ],
477
+ "items": 24,
478
+ "node": [
479
+ {
480
+ "key": "2010-03",
481
+ "labels": [
482
+ {
483
+ "lang": "FR",
484
+ "region": "FR",
485
+ "label": "03"
486
+ }
487
+ ],
488
+ "items": 14,
489
+ "node": [
490
+ {
491
+ "key": "2010-03-07",
492
+ "labels": [
493
+ {
494
+ "lang": "FR",
495
+ "region": "FR",
496
+ "label": "07"
497
+ }
498
+ ],
499
+ "items": 4
500
+ }
501
+ ]
502
+ }
503
+ ]
504
+ }
505
+ ],
506
+ "layout": "TREE",
507
+ "type": "DATE",
508
+ "id": "TREE_DATE",
509
+ "labels": [
510
+ {
511
+ "label": "Tree date"
512
+ }
513
+ ]
514
+ }');
515
+
516
+ $query = new AfsQuery();
517
+ $config = new AfsHelperConfiguration();
518
+ $config->set_helper_format(AfsHelperFormat::HELPERS);
519
+ $facet_mgr = $query->get_facet_manager();
520
+ $facet_mgr->add_facet(new AfsFacet('TREE_DATE', AfsFacetType::DATE_TYPE));
521
+ $builder = new AfsFacetElementBuilder($facet_mgr, $query);
522
+ $elems = $builder->create_elements('TREE_DATE', $input, $config);
523
+
524
+ $this->assertEquals(count($elems), 1);
525
+ $elem = reset($elems);
526
+ $this->assertEquals($elem->label, '2010');
527
+ $this->assertEquals($elem->count, 24);
528
+ $this->assertFalse($elem->active);
529
+ $this->assertTrue($elem->query->has_filter('TREE_DATE', '"2010"'));
530
+ $this->assertEquals(count($elem->values), 1);
531
+ $elem = $elem->values[0];
532
+ $this->assertEquals($elem->label, '03');
533
+ $this->assertEquals($elem->count, 14);
534
+ $this->assertFalse($elem->active);
535
+ $this->assertTrue($elem->query->has_filter('TREE_DATE', '"2010-03"'));
536
+ $this->assertEquals(count($elem->values), 1);
537
+ $elem = $elem->values[0];
538
+ $this->assertEquals($elem->label, '07');
539
+ $this->assertEquals($elem->count, 4);
540
+ $this->assertFalse($elem->active);
541
+ $this->assertTrue($elem->query->has_filter('TREE_DATE', '"2010-03-07"'));
542
+ $this->assertEquals(count($elem->values), 0);
543
+ }
544
+
545
+ public function testFacetElementBuilderReplaceFilter()
546
+ {
547
+ $input = json_decode('{
548
+ "afs:t": "FacetTree",
549
+ "node": [
550
+ {
551
+ "key": "false",
552
+ "labels": [
553
+ {
554
+ "label": "BAD"
555
+ }
556
+ ],
557
+ "items": 67
558
+ },
559
+ {
560
+ "key": "true",
561
+ "labels": [
562
+ {
563
+ "label": "GOOD"
564
+ }
565
+ ],
566
+ "items": 133
567
+ }
568
+ ],
569
+ "layout": "TREE",
570
+ "type": "BOOL",
571
+ "id": "BOOL",
572
+ "labels": [
573
+ {
574
+ "label": "Boolean facet"
575
+ }
576
+ ]
577
+ }');
578
+
579
+ $query = new AfsQuery();
580
+ $query = $query->add_filter('BOOL', 'false');
581
+ $config = new AfsHelperConfiguration();
582
+ $config->set_helper_format(AfsHelperFormat::HELPERS);
583
+ $facet_mgr = $query->get_facet_manager();
584
+ $facet_mgr->add_facet(new AfsFacet('BOOL', AfsFacetType::BOOL_TYPE, AfsFacetLayout::TREE, AfsFacetMode::SINGLE_MODE));
585
+ $builder = new AfsFacetElementBuilder($facet_mgr, $query);
586
+ $elems = $builder->create_elements('BOOL', $input, $config);
587
+
588
+ $this->assertEquals(count($elems), 2);
589
+ $elem = reset($elems);
590
+ $this->assertEquals($elem->label, 'BAD');
591
+ $this->assertEquals($elem->count, 67);
592
+ $this->assertTrue($elem->active);
593
+ $this->assertFalse($elem->query->has_filter('BOOL', 'false'));
594
+ $this->assertEquals(count($elem->values), 0);
595
+ next($elems);
596
+ $elem = current($elems);
597
+ $this->assertEquals($elem->label, 'GOOD');
598
+ $this->assertEquals($elem->count, 133);
599
+ $this->assertFalse($elem->active);
600
+ $this->assertTrue($elem->query->has_filter('BOOL', 'true'));
601
+ $this->assertFalse($elem->query->has_filter('BOOL', 'false'));
602
+ $this->assertEquals(count($elem->values), 0);
603
+ }
604
+
605
+ public function testFacetElementBuilderAddFilter()
606
+ {
607
+ $input = json_decode('{
608
+ "afs:t": "FacetTree",
609
+ "node": [
610
+ {
611
+ "key": "false",
612
+ "labels": [
613
+ {
614
+ "label": "BAD"
615
+ }
616
+ ],
617
+ "items": 67
618
+ },
619
+ {
620
+ "key": "true",
621
+ "labels": [
622
+ {
623
+ "label": "GOOD"
624
+ }
625
+ ],
626
+ "items": 133
627
+ }
628
+ ],
629
+ "layout": "TREE",
630
+ "type": "BOOL",
631
+ "id": "BOOL",
632
+ "labels": [
633
+ {
634
+ "label": "Boolean facet"
635
+ }
636
+ ]
637
+ }');
638
+
639
+ $query = new AfsQuery();
640
+ $query = $query->add_filter('BOOL', 'false');
641
+
642
+ $config = new AfsHelperConfiguration();
643
+ $config->set_helper_format(AfsHelperFormat::HELPERS);
644
+ $facet_mgr = $query->get_facet_manager();
645
+ $facet_mgr->add_facet(new AfsFacet('BOOL', AfsFacetType::BOOL_TYPE, AfsFacetLayout::TREE, AfsFacetMode::OR_MODE));
646
+ $builder = new AfsFacetElementBuilder($facet_mgr, $query);
647
+ $elems = $builder->create_elements('BOOL', $input, $config);
648
+
649
+ $this->assertEquals(count($elems), 2);
650
+ $elem = reset($elems);
651
+ $this->assertEquals($elem->label, 'BAD');
652
+ $this->assertEquals($elem->count, 67);
653
+ $this->assertTrue($elem->active);
654
+ $this->assertFalse($elem->query->has_filter('BOOL', 'false'));
655
+ $this->assertEquals(count($elem->values), 0);
656
+ next($elems);
657
+ $elem = current($elems);
658
+ $this->assertEquals($elem->label, 'GOOD');
659
+ $this->assertEquals($elem->count, 133);
660
+ $this->assertFalse($elem->active);
661
+ $this->assertTrue($elem->query->has_filter('BOOL', 'true'));
662
+ $this->assertTrue($elem->query->has_filter('BOOL', 'false'));
663
+ $this->assertEquals(count($elem->values), 0);
664
+ }
665
+
666
+ public function testFacetWithoutLabel()
667
+ {
668
+ $input = json_decode('{
669
+ "afs:t": "FacetTree",
670
+ "node": [
671
+ {
672
+ "key": "false",
673
+ "labels": [
674
+ {
675
+ "label": "BAD"
676
+ }
677
+ ],
678
+ "items": 67
679
+ },
680
+ {
681
+ "key": "true",
682
+ "labels": [
683
+ {
684
+ "label": "GOOD"
685
+ }
686
+ ],
687
+ "items": 133
688
+ }
689
+ ],
690
+ "layout": "TREE",
691
+ "type": "BOOL",
692
+ "id": "BOOOOL"
693
+ }');
694
+
695
+ $config = new AfsHelperConfiguration();
696
+ $config->set_helper_format(AfsHelperFormat::HELPERS);
697
+ $query = new AfsQuery();
698
+ $facet = new AfsFacetHelper($input, $query, $config);
699
+
700
+ $this->assertEquals('BOOOOL', $facet->get_label());
701
+ }
702
+ }
lib/antidot/AFS/SEARCH/TEST/pagerHelperTest.php CHANGED
@@ -40,16 +40,16 @@ class PagerHelperTest extends PHPUnit_Framework_TestCase
40
  new AfsHelperConfiguration());
41
  try {
42
  $helper->get_previous();
43
- $this->fail('No previous page available should have rosen exception!');
44
  } catch (OutOfBoundsException $e) { }
45
- $this->assertEquals($helper->get_next()->get_page(), 2);
46
 
47
  $pages = $helper->get_pages();
48
  $this->assertEquals(count($pages), 2);
49
  $this->assertTrue(array_key_exists(1, $pages));
50
- $this->assertEquals($pages[1]->get_page(), '1');
51
  $this->assertTrue(array_key_exists(2, $pages));
52
- $this->assertEquals($pages[2]->get_page(), '2');
53
  $this->assertEquals($helper->get_current_no(), 1);
54
  }
55
 
@@ -73,16 +73,16 @@ class PagerHelperTest extends PHPUnit_Framework_TestCase
73
  $helper->get_next();
74
  $this->fail('No next page available should have rosen exception!');
75
  } catch (OutOfBoundsException $e) { }
76
- $this->assertEquals($helper->get_previous()->get_page(), 2);
77
 
78
  $pages = $helper->get_pages();
79
  $this->assertEquals(count($pages), 3);
80
  $this->assertTrue(array_key_exists(1, $pages));
81
- $this->assertEquals($pages[1]->get_page(), '1');
82
  $this->assertTrue(array_key_exists(2, $pages));
83
- $this->assertEquals($pages[2]->get_page(), '2');
84
  $this->assertTrue(array_key_exists(3, $pages));
85
- $this->assertEquals($pages[3]->get_page(), '3');
86
  $this->assertEquals($helper->get_current_no(), 3);
87
  }
88
 
@@ -104,10 +104,10 @@ class PagerHelperTest extends PHPUnit_Framework_TestCase
104
  new AfsHelperConfiguration());
105
  $format = $helper->format();
106
  $this->assertFalse(array_key_exists('next', $format['pages']));
107
- $this->assertEquals($format['pages']['previous']->get_page(), 2);
108
- $this->assertEquals($format['pages'][1]->get_page(), '1');
109
- $this->assertEquals($format['pages'][2]->get_page(), '2');
110
- $this->assertEquals($format['pages'][3]->get_page(), '3');
111
  $this->assertEquals($format['current'], 3);
112
  }
113
 
@@ -130,16 +130,16 @@ class PagerHelperTest extends PHPUnit_Framework_TestCase
130
  $config->set_query_coder(new AfsQueryCoder('foo.php'));
131
  $helper = new AfsPagerHelper($input->pager, $this->meta, new AfsQuery(), $config);
132
  $this->assertEquals($helper->get_previous(), 'foo.php?replies=10');
133
- $this->assertEquals('foo.php?replies=10&page=3', $helper->get_next());
134
 
135
  $pages = $helper->get_pages();
136
  $this->assertEquals(count($pages), 3);
137
  $this->assertTrue(array_key_exists(1, $pages));
138
  $this->assertEquals($pages[1], 'foo.php?replies=10');
139
  $this->assertTrue(array_key_exists(2, $pages));
140
- $this->assertEquals('foo.php?replies=10&page=2', $pages[2]);
141
  $this->assertTrue(array_key_exists(3, $pages));
142
- $this->assertEquals('foo.php?replies=10&page=3', $pages[3]);
143
  $this->assertEquals($helper->get_current_no(), 2);
144
  }
145
 
@@ -164,10 +164,10 @@ class PagerHelperTest extends PHPUnit_Framework_TestCase
164
  $format = $helper->format();
165
 
166
  $this->assertEquals('foo.php?replies=10', $format['pages']['previous']);
167
- $this->assertEquals('foo.php?replies=10&page=3', $format['pages']['next']);
168
  $this->assertEquals('foo.php?replies=10', $format['pages'][1]);
169
- $this->assertEquals('foo.php?replies=10&page=2', $format['pages'][2]);
170
- $this->assertEquals('foo.php?replies=10&page=3', $format['pages'][3]);
171
  $this->assertEquals($format['current'], 2);
172
  }
173
 
@@ -195,7 +195,7 @@ class PagerHelperTest extends PHPUnit_Framework_TestCase
195
  $this->assertEquals('foo.php?replies=10', $key_value['value']);
196
  $key_value = each($pages);
197
  $this->assertEquals('2', $key_value['key']);
198
- $this->assertEquals('foo.php?replies=10&page=2', $key_value['value']);
199
  }
200
 
201
  public function testRetrieveAllPagesWithPreviousWithoutNext()
@@ -220,13 +220,13 @@ class PagerHelperTest extends PHPUnit_Framework_TestCase
220
  $this->assertEquals(3, count($pages));
221
  $key_value = each($pages);
222
  $this->assertEquals('previous', $key_value['key']);
223
- $this->assertEquals('foo.php?replies=10&page=42', $key_value['value']);
224
  $key_value = each($pages);
225
  $this->assertEquals('1', $key_value['key']);
226
  $this->assertEquals('foo.php?replies=10', $key_value['value']);
227
  $key_value = each($pages);
228
  $this->assertEquals('2', $key_value['key']);
229
- $this->assertEquals('foo.php?replies=10&page=2', $key_value['value']);
230
  }
231
 
232
  public function testRetrieveAllPagesWithoutPreviousWithNext()
@@ -254,10 +254,10 @@ class PagerHelperTest extends PHPUnit_Framework_TestCase
254
  $this->assertEquals('foo.php?replies=10', $key_value['value']);
255
  $key_value = each($pages);
256
  $this->assertEquals('2', $key_value['key']);
257
- $this->assertEquals('foo.php?replies=10&page=2', $key_value['value']);
258
  $key_value = each($pages);
259
  $this->assertEquals('next', $key_value['key']);
260
- $this->assertEquals('foo.php?replies=10&page=666', $key_value['value']);
261
  }
262
 
263
  public function testRetrieveAllPagesWithPreviousAndNext()
@@ -283,16 +283,16 @@ class PagerHelperTest extends PHPUnit_Framework_TestCase
283
  $this->assertEquals(4, count($pages));
284
  $key_value = each($pages);
285
  $this->assertEquals('previous', $key_value['key']);
286
- $this->assertEquals('foo.php?replies=10&page=42', $key_value['value']);
287
  $key_value = each($pages);
288
  $this->assertEquals('1', $key_value['key']);
289
  $this->assertEquals('foo.php?replies=10', $key_value['value']);
290
  $key_value = each($pages);
291
  $this->assertEquals('2', $key_value['key']);
292
- $this->assertEquals('foo.php?replies=10&page=2', $key_value['value']);
293
  $key_value = each($pages);
294
  $this->assertEquals('next', $key_value['key']);
295
- $this->assertEquals('foo.php?replies=10&page=666', $key_value['value']);
296
  }
297
 
298
  public function testComputedLastPage1()
@@ -326,7 +326,7 @@ class PagerHelperTest extends PHPUnit_Framework_TestCase
326
  $this->assertEquals(7, $helper->get_last_page_no());
327
  $page_info = $helper->get_last_page();
328
  $this->assertEquals(7, $page_info[0]);
329
- $this->assertEquals(7, $page_info[1]->get_page());
330
  }
331
  public function testComputedLastPage2()
332
  {
40
  new AfsHelperConfiguration());
41
  try {
42
  $helper->get_previous();
43
+ $this->fail('No previous page available should have frozen exception!');
44
  } catch (OutOfBoundsException $e) { }
45
+ $this->assertEquals($helper->get_next()->get_page('Catalog'), 2);
46
 
47
  $pages = $helper->get_pages();
48
  $this->assertEquals(count($pages), 2);
49
  $this->assertTrue(array_key_exists(1, $pages));
50
+ $this->assertEquals($pages[1]->get_page('Catalog'), 1);
51
  $this->assertTrue(array_key_exists(2, $pages));
52
+ $this->assertEquals($pages[2]->get_page('Catalog'), 2);
53
  $this->assertEquals($helper->get_current_no(), 1);
54
  }
55
 
73
  $helper->get_next();
74
  $this->fail('No next page available should have rosen exception!');
75
  } catch (OutOfBoundsException $e) { }
76
+ $this->assertEquals($helper->get_previous()->get_page('Catalog'), 2);
77
 
78
  $pages = $helper->get_pages();
79
  $this->assertEquals(count($pages), 3);
80
  $this->assertTrue(array_key_exists(1, $pages));
81
+ $this->assertEquals($pages[1]->get_page('Catalog'), '1');
82
  $this->assertTrue(array_key_exists(2, $pages));
83
+ $this->assertEquals($pages[2]->get_page('Catalog'), '2');
84
  $this->assertTrue(array_key_exists(3, $pages));
85
+ $this->assertEquals($pages[3]->get_page('Catalog'), '3');
86
  $this->assertEquals($helper->get_current_no(), 3);
87
  }
88
 
104
  new AfsHelperConfiguration());
105
  $format = $helper->format();
106
  $this->assertFalse(array_key_exists('next', $format['pages']));
107
+ $this->assertEquals($format['pages']['previous']->get_page('Catalog'), 2);
108
+ $this->assertEquals($format['pages'][1]->get_page('Catalog'), '1');
109
+ $this->assertEquals($format['pages'][2]->get_page('Catalog'), '2');
110
+ $this->assertEquals($format['pages'][3]->get_page('Catalog'), '3');
111
  $this->assertEquals($format['current'], 3);
112
  }
113
 
130
  $config->set_query_coder(new AfsQueryCoder('foo.php'));
131
  $helper = new AfsPagerHelper($input->pager, $this->meta, new AfsQuery(), $config);
132
  $this->assertEquals($helper->get_previous(), 'foo.php?replies=10');
133
+ $this->assertEquals('foo.php?replies=10&page@Catalog=3', $helper->get_next());
134
 
135
  $pages = $helper->get_pages();
136
  $this->assertEquals(count($pages), 3);
137
  $this->assertTrue(array_key_exists(1, $pages));
138
  $this->assertEquals($pages[1], 'foo.php?replies=10');
139
  $this->assertTrue(array_key_exists(2, $pages));
140
+ $this->assertEquals('foo.php?replies=10&page@Catalog=2', $pages[2]);
141
  $this->assertTrue(array_key_exists(3, $pages));
142
+ $this->assertEquals('foo.php?replies=10&page@Catalog=3', $pages[3]);
143
  $this->assertEquals($helper->get_current_no(), 2);
144
  }
145
 
164
  $format = $helper->format();
165
 
166
  $this->assertEquals('foo.php?replies=10', $format['pages']['previous']);
167
+ $this->assertEquals('foo.php?replies=10&page@Catalog=3', $format['pages']['next']);
168
  $this->assertEquals('foo.php?replies=10', $format['pages'][1]);
169
+ $this->assertEquals('foo.php?replies=10&page@Catalog=2', $format['pages'][2]);
170
+ $this->assertEquals('foo.php?replies=10&page@Catalog=3', $format['pages'][3]);
171
  $this->assertEquals($format['current'], 2);
172
  }
173
 
195
  $this->assertEquals('foo.php?replies=10', $key_value['value']);
196
  $key_value = each($pages);
197
  $this->assertEquals('2', $key_value['key']);
198
+ $this->assertEquals('foo.php?replies=10&page@Catalog=2', $key_value['value']);
199
  }
200
 
201
  public function testRetrieveAllPagesWithPreviousWithoutNext()
220
  $this->assertEquals(3, count($pages));
221
  $key_value = each($pages);
222
  $this->assertEquals('previous', $key_value['key']);
223
+ $this->assertEquals('foo.php?replies=10&page@Catalog=42', $key_value['value']);
224
  $key_value = each($pages);
225
  $this->assertEquals('1', $key_value['key']);
226
  $this->assertEquals('foo.php?replies=10', $key_value['value']);
227
  $key_value = each($pages);
228
  $this->assertEquals('2', $key_value['key']);
229
+ $this->assertEquals('foo.php?replies=10&page@Catalog=2', $key_value['value']);
230
  }
231
 
232
  public function testRetrieveAllPagesWithoutPreviousWithNext()
254
  $this->assertEquals('foo.php?replies=10', $key_value['value']);
255
  $key_value = each($pages);
256
  $this->assertEquals('2', $key_value['key']);
257
+ $this->assertEquals('foo.php?replies=10&page@Catalog=2', $key_value['value']);
258
  $key_value = each($pages);
259
  $this->assertEquals('next', $key_value['key']);
260
+ $this->assertEquals('foo.php?replies=10&page@Catalog=666', $key_value['value']);
261
  }
262
 
263
  public function testRetrieveAllPagesWithPreviousAndNext()
283
  $this->assertEquals(4, count($pages));
284
  $key_value = each($pages);
285
  $this->assertEquals('previous', $key_value['key']);
286
+ $this->assertEquals('foo.php?replies=10&page@Catalog=42', $key_value['value']);
287
  $key_value = each($pages);
288
  $this->assertEquals('1', $key_value['key']);
289
  $this->assertEquals('foo.php?replies=10', $key_value['value']);
290
  $key_value = each($pages);
291
  $this->assertEquals('2', $key_value['key']);
292
+ $this->assertEquals('foo.php?replies=10&page@Catalog=2', $key_value['value']);
293
  $key_value = each($pages);
294
  $this->assertEquals('next', $key_value['key']);
295
+ $this->assertEquals('foo.php?replies=10&page@Catalog=666', $key_value['value']);
296
  }
297
 
298
  public function testComputedLastPage1()
326
  $this->assertEquals(7, $helper->get_last_page_no());
327
  $page_info = $helper->get_last_page();
328
  $this->assertEquals(7, $page_info[0]);
329
+ $this->assertEquals(7, $page_info[1]->get_page('Catalog'));
330
  }
331
  public function testComputedLastPage2()
332
  {
lib/antidot/AFS/SEARCH/TEST/promoteBannerReplyHelper.php ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Created by PhpStorm.
4
+ * User: ct
5
+ * Date: 2/13/15
6
+ * Time: 4:11 PM
7
+ */
8
+ require_once 'AFS/SEARCH/afs_promote_banner_reply_helper.php';
9
+
10
+
11
+ class PromoteBannerHelperTest extends PHPUnit_Framework_TestCase {
12
+
13
+ protected function setUp()
14
+ {
15
+ $client_data = '<afs:type xmlns:afs=\"http://ref.antidot.net/7.3/bo.xsd\">banner</afs:type><afs:images xmlns:afs=\"http://ref.antidot.net/7.3/bo.xsd\"><afs:image><afs:url>url</afs:url><afs:imageUrl>image_url</afs:imageUrl></afs:image></afs:images>';
16
+ $this->input = json_decode('{
17
+ "docId": 198,
18
+ "uri": "http://foo.bar.baz/116",
19
+ "title": [
20
+ {
21
+ "afs:t": "KwicString",
22
+ "text": "The title"
23
+ }
24
+ ],
25
+ "abstract": [
26
+ {
27
+ "afs:t": "KwicString",
28
+ "text": "viens de tomber a monté d\'un nouveau cran dans l\'étrangeté. Jamais dans l\'Histoire de l\'humanité il n\'a existé de civilisation sans enfants. Je tente d\'en imaginer les conséquences. George, qui m\'a deviné, énumère: - Comme nous ne nous reproduisons pas, la moitié féminine de l\'humanité"
29
+ },
30
+ { "afs:t": "KwicTruncate" }
31
+ ],
32
+ "relevance": {
33
+ "rank": 3
34
+ },
35
+ "clientData": [
36
+ {
37
+ "contents": "' . $client_data . '",
38
+ "id": "main",
39
+ "mimeType": "text/xml"
40
+ }]
41
+ }');
42
+
43
+ $this->check_json_error();
44
+ }
45
+
46
+ private function check_json_error() {
47
+ switch (json_last_error()) {
48
+ case JSON_ERROR_NONE:
49
+ break;
50
+ case JSON_ERROR_DEPTH:
51
+ throw new Exception(' - Max depth reached');
52
+ break;
53
+ case JSON_ERROR_STATE_MISMATCH:
54
+ throw new Exception(' - Bad modes or underflow');
55
+ break;
56
+ case JSON_ERROR_CTRL_CHAR:
57
+ throw new Exception(' - Bad characters');
58
+ break;
59
+ case JSON_ERROR_SYNTAX:
60
+ throw new Exception(' - Syntax error');
61
+ break;
62
+ case JSON_ERROR_UTF8:
63
+ throw new Exception(' - Bad encoding');
64
+ break;
65
+ default:
66
+ break;
67
+ }
68
+ }
69
+
70
+ public function testUrls() {
71
+ $promote_banner_helper = new AfsPromoteBannerReplyHelper($this->input);
72
+ $this->assertEquals($promote_banner_helper->get_url(), 'url');
73
+ $this->assertEquals($promote_banner_helper->get_image_url(), 'image_url');
74
+ }
75
+
76
+ /*public function testWithJsonClientData() {
77
+ $input = json_decode('{
78
+ "docId": 198,
79
+ "uri": "http://foo.bar.baz/116",
80
+ "clientData": [
81
+ {
82
+ "contents": {
83
+ "type": "banner",
84
+ "images": {
85
+ "image": {
86
+ "url": "url",
87
+ "imageUrl" : "image_url"
88
+ }
89
+ }
90
+
91
+ },
92
+ "id": "main",
93
+ "mimeType": "application/json"
94
+ }
95
+ ]}');
96
+
97
+ $promote_banner_helper = new AfsPromoteBannerReplyHelper($input);
98
+ $this->assertEquals($promote_banner_helper->get_url(), 'url');
99
+ $this->assertEquals($promote_banner_helper->get_image_url(), 'image_url');
100
+ }*/
101
+ }
lib/antidot/AFS/SEARCH/TEST/promoteRedirectReplyHelper.php ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Created by PhpStorm.
4
+ * User: ct
5
+ * Date: 2/13/15
6
+ * Time: 4:56 PM
7
+ */
8
+
9
+ require_once 'AFS/SEARCH/afs_promote_redirect_reply_helper.php';
10
+
11
+
12
+ class PromoteRedirectReplyHelperTest extends PHPUnit_Framework_TestCase {
13
+
14
+ protected function setUp()
15
+ {
16
+ $client_data = '<afs:type xmlns:afs=\"http://ref.antidot.net/7.3/bo.xsd\">redirection</afs:type>';
17
+ $this->input = json_decode('{
18
+ "docId": 198,
19
+ "uri": "http://url/for/redirection",
20
+ "clientData": [
21
+ {
22
+ "contents": "' . $client_data . '",
23
+ "id": "main",
24
+ "mimeType": "text/xml"
25
+ }]
26
+ }');
27
+
28
+ $this->check_json_error();
29
+ }
30
+
31
+ private function check_json_error() {
32
+ switch (json_last_error()) {
33
+ case JSON_ERROR_NONE:
34
+ break;
35
+ case JSON_ERROR_DEPTH:
36
+ throw new Exception(' - Max depth reached');
37
+ break;
38
+ case JSON_ERROR_STATE_MISMATCH:
39
+ throw new Exception(' - Bad modes or underflow');
40
+ break;
41
+ case JSON_ERROR_CTRL_CHAR:
42
+ throw new Exception(' - Bad characters');
43
+ break;
44
+ case JSON_ERROR_SYNTAX:
45
+ throw new Exception(' - Syntax error');
46
+ break;
47
+ case JSON_ERROR_UTF8:
48
+ throw new Exception(' - Bad encoding');
49
+ break;
50
+ default:
51
+ break;
52
+ }
53
+ }
54
+
55
+ public function testUrls() {
56
+ $promote_banner_helper = new AfsPromoteRedirectReplyHelper($this->input);
57
+ $this->assertEquals($promote_banner_helper->get_url(), 'http://url/for/redirection');
58
+ }
59
+ }
lib/antidot/AFS/SEARCH/TEST/promoteReplysetHelperTest.php CHANGED
@@ -5,6 +5,7 @@ class PromoteReplysetHelperTest extends PHPUnit_Framework_TestCase
5
  {
6
  public function testBlabla()
7
  {
 
8
  $input = json_decode('{
9
  "header": {
10
  "query": {
@@ -101,7 +102,7 @@ class PromoteReplysetHelperTest extends PHPUnit_Framework_TestCase
101
  },
102
  "clientData": [
103
  {
104
- "contents": "<clientdata>{&quot;data&quot;: [{&quot;data1&quot;: &quot;data 0&quot;}, {&quot;data1&quot;: &quot;data 1&quot;}, {&quot;m1&quot;: &quot;m 1&quot;, &quot;m0&quot;: &quot;m 0&quot;, &quot;m3&quot;: &quot;m 3&quot;, &quot;m2&quot;: &quot;m 2&quot;}]}</clientdata>",
105
  "id": "main",
106
  "mimeType": "text/xml"
107
  }
@@ -138,7 +139,7 @@ class PromoteReplysetHelperTest extends PHPUnit_Framework_TestCase
138
  },
139
  "clientData": [
140
  {
141
- "contents": "<clientdata>&lt;data&gt;&lt;data1&gt;data 0&lt;/data1&gt;&lt;data1&gt;data 1&lt;/data1&gt;&lt;multi&gt;&lt;m0&gt;m 0&lt;/m0&gt;&lt;m1&gt;m 1&lt;/m1&gt;&lt;m2&gt;m 2&lt;/m2&gt;&lt;m3&gt;m 3&lt;/m3&gt;&lt;/multi&gt;&lt;/data&gt;</clientdata>",
142
  "id": "main",
143
  "mimeType": "text/xml"
144
  }
@@ -170,6 +171,8 @@ class PromoteReplysetHelperTest extends PHPUnit_Framework_TestCase
170
  $replies = $helper->get_replies();
171
  $this->assertEquals('The title 116', $replies[0]->title);
172
  $this->assertEquals('The title 81', $replies[1]->title);
 
 
173
  // and so on...
174
  }
175
  }
5
  {
6
  public function testBlabla()
7
  {
8
+ $client_data = '<afs:type xmlns:afs=\"http://ref.antidot.net/7.3/bo.xsd\">default</afs:type><afs:customData xmlns:afs=\"http://ref.antidot.net/7.3/bo.xsd\"><afs:key1>v1</afs:key1></afs:customData>';
9
  $input = json_decode('{
10
  "header": {
11
  "query": {
102
  },
103
  "clientData": [
104
  {
105
+ "contents": "' . $client_data . '",
106
  "id": "main",
107
  "mimeType": "text/xml"
108
  }
139
  },
140
  "clientData": [
141
  {
142
+ "contents": "' . $client_data . '",
143
  "id": "main",
144
  "mimeType": "text/xml"
145
  }
171
  $replies = $helper->get_replies();
172
  $this->assertEquals('The title 116', $replies[0]->title);
173
  $this->assertEquals('The title 81', $replies[1]->title);
174
+ $custom_data = $replies[0]->get_custom_data();
175
+ $this->assertEquals(array("key1" => "v1"), $custom_data);
176
  // and so on...
177
  }
178
  }
lib/antidot/AFS/SEARCH/TEST/queryCoderTest.php CHANGED
@@ -43,4 +43,13 @@ class QueryCoderTest extends PHPUnit_Framework_TestCase
43
  $this->assertFalse($query->has_query());
44
  // and so on
45
  }
 
 
 
 
 
 
 
 
 
46
  }
43
  $this->assertFalse($query->has_query());
44
  // and so on
45
  }
46
+
47
+ public function testBuildQueryFromFeedFilterParameter()
48
+ {
49
+ $coder = new AfsQueryCoder();
50
+ $query = $coder->build_query(array('filter@Catalog' => 'FOO_bar_baz'));
51
+ $this->assertEquals(1, count($query->get_filters()));
52
+ $this->assertFalse($query->has_filter('FOO', 'bat', 'feed'));
53
+ $this->assertFalse($query->has_filter('FOO', 'baz', 'feed'));
54
+ }
55
  }
lib/antidot/AFS/SEARCH/TEST/queryTest.php CHANGED
@@ -11,6 +11,10 @@ class QueryTest extends PHPUnit_Framework_TestCase
11
  $query = new AfsQuery();
12
  $query = $query->set_query('foo');
13
  $this->assertTrue($query->get_query() == 'foo');
 
 
 
 
14
  }
15
  public function testSetNewQueryValue()
16
  {
@@ -19,20 +23,46 @@ class QueryTest extends PHPUnit_Framework_TestCase
19
  $query = $query->set_query('bar');
20
  $this->assertFalse($query->get_query() == 'foo');
21
  $this->assertTrue($query->get_query() == 'bar');
 
 
 
 
 
22
  }
23
 
24
  public function testHasNoQuery()
25
  {
26
  $query = new AfsQuery();
27
  $this->assertFalse($query->has_query());
 
28
  }
29
  public function testHasQuery()
30
  {
31
  $query = new AfsQuery();
32
  $query = $query->set_query('foo');
 
33
  $this->assertTrue($query->has_query());
 
34
  }
35
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  public function testAddFilterValue()
37
  {
38
  $query = new AfsQuery();
@@ -146,6 +176,12 @@ class QueryTest extends PHPUnit_Framework_TestCase
146
  } catch (Exception $e) {
147
  $this->fail('Exception raised: ' . $e);
148
  }
 
 
 
 
 
 
149
  }
150
  public function testRemoveUnexistingFilterValue()
151
  {
@@ -156,13 +192,23 @@ class QueryTest extends PHPUnit_Framework_TestCase
156
  } catch (Exception $e) {
157
  $this->fail('Exception raised: ' . $e);
158
  }
 
 
 
 
 
 
 
159
  }
160
  public function testRemoveExistingFilterValue()
161
  {
162
  $query = new AfsQuery();
163
  $query = $query->add_filter('foo', 'bar');
 
164
  $query = $query->remove_filter('foo', 'bar');
 
165
  $this->assertFalse($query->has_filter('foo', 'bar'));
 
166
  }
167
 
168
  public function testGetListOfValuesForUnexistingFilter()
@@ -175,6 +221,18 @@ class QueryTest extends PHPUnit_Framework_TestCase
175
  }
176
  $this->fail('Getting values from unexisting filter should raise exception!');
177
  }
 
 
 
 
 
 
 
 
 
 
 
 
178
  public function testGetListOfFilterValues()
179
  {
180
  $query = new AfsQuery();
@@ -185,6 +243,8 @@ class QueryTest extends PHPUnit_Framework_TestCase
185
  $this->assertTrue(in_array('baz', $values));
186
  }
187
 
 
 
188
  public function testGetEmptyListOfFilters()
189
  {
190
  $query = new AfsQuery();
@@ -266,6 +326,13 @@ class QueryTest extends PHPUnit_Framework_TestCase
266
  $this->assertTrue(in_array('foo', $query->get_feeds()));
267
  $this->assertTrue(in_array('bar', $query->get_feeds()));
268
  }
 
 
 
 
 
 
 
269
  public function testResetFeedName()
270
  {
271
  $query = new AfsQuery();
@@ -399,6 +466,15 @@ class QueryTest extends PHPUnit_Framework_TestCase
399
  $this->assertTrue($query->has_sort('afs:relevance'));
400
  $this->assertEquals(AfsSortOrder::DESC, $query->get_sort_order('afs:relevance'));
401
  }
 
 
 
 
 
 
 
 
 
402
  public function testResetSortOrder()
403
  {
404
  $query = new AfsQuery();
@@ -664,6 +740,13 @@ class QueryTest extends PHPUnit_Framework_TestCase
664
  $this->assertEquals($query->get_key(), 'test');
665
  }
666
 
 
 
 
 
 
 
 
667
  public function testCloneQuery()
668
  {
669
  $query = new AfsQuery();
@@ -737,6 +820,11 @@ class QueryTest extends PHPUnit_Framework_TestCase
737
  $query = $query->add_filter('fox', 'bat');
738
  $query = $query->add_filter('fox', 'bas');
739
 
 
 
 
 
 
740
  $query = $query->add_feed('feed');
741
  $query = $query->add_feed('food');
742
 
@@ -774,6 +862,14 @@ class QueryTest extends PHPUnit_Framework_TestCase
774
  $this->assertTrue(in_array('bat', $result['filter']['fox']));
775
  $this->assertTrue(in_array('bas', $result['filter']['fox']));
776
 
 
 
 
 
 
 
 
 
777
  $this->assertTrue(array_key_exists('feed', $result));
778
  $this->assertTrue(in_array('feed', $result['feed']));
779
  $this->assertTrue(in_array('food', $result['feed']));
@@ -825,6 +921,8 @@ class QueryTest extends PHPUnit_Framework_TestCase
825
  'query' => 'query',
826
  'filter' => array('foo' => array('bar', 'baz'),
827
  'fox' => array('bat', 'bas')),
 
 
828
  'feed' => array('feed', 'food'),
829
  'replies' => 666,
830
  'lang' => 'en',
@@ -848,6 +946,13 @@ class QueryTest extends PHPUnit_Framework_TestCase
848
  $this->assertTrue(in_array('bat', $query->get_filter_values('fox')));
849
  $this->assertTrue(in_array('bas', $query->get_filter_values('fox')));
850
 
 
 
 
 
 
 
 
851
  $this->assertTrue($query->has_feed());
852
  $this->assertTrue(in_array('feed', $query->get_feeds()));
853
  $this->assertTrue(in_array('food', $query->get_feeds()));
@@ -985,6 +1090,7 @@ class QueryTest extends PHPUnit_Framework_TestCase
985
  $this->assertTrue($facet_mgr->has_facet('FOO'));
986
  $facet = $facet_mgr->get_facet('FOO');
987
  $this->assertTrue($facet->has_single_mode());
 
988
  }
989
  public function testFacetsSingleValuedAsList()
990
  {
@@ -1022,6 +1128,145 @@ class QueryTest extends PHPUnit_Framework_TestCase
1022
  $query = $query->set_facet_order(array('foo', 'bar'), AfsFacetOrder::STRICT);
1023
  $this->assertTrue($query->get_facet_manager()->is_facet_order_strict());
1024
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1025
  }
1026
 
1027
 
11
  $query = new AfsQuery();
12
  $query = $query->set_query('foo');
13
  $this->assertTrue($query->get_query() == 'foo');
14
+
15
+ $query = $query->set_query('foo', 'feed');
16
+ $this->assertFalse($query->has_feed('feed'));
17
+ $this->assertTrue($query->get_query('feed') == 'foo');
18
  }
19
  public function testSetNewQueryValue()
20
  {
23
  $query = $query->set_query('bar');
24
  $this->assertFalse($query->get_query() == 'foo');
25
  $this->assertTrue($query->get_query() == 'bar');
26
+
27
+ $query = $query->set_query('foo', 'feed');
28
+ $query = $query->set_query('bar', 'feed');
29
+ $this->assertFalse($query->get_query('feed') == 'foo');
30
+ $this->assertTrue($query->get_query('feed') == 'bar');
31
  }
32
 
33
  public function testHasNoQuery()
34
  {
35
  $query = new AfsQuery();
36
  $this->assertFalse($query->has_query());
37
+ $this->assertFalse($query->has_query('feed'));
38
  }
39
  public function testHasQuery()
40
  {
41
  $query = new AfsQuery();
42
  $query = $query->set_query('foo');
43
+ $query = $query->set_query('foo', 'feed');
44
  $this->assertTrue($query->has_query());
45
+ $this->assertTrue($query->has_query('feed'));
46
  }
47
 
48
+ public function testaddFeedFilterValue() {
49
+ $query = new AfsQuery();
50
+ $query = $query->add_filter_on_feed('foo', array('bar'), 'feed');
51
+ $this->assertTrue($query->has_filter('foo', 'bar', 'feed'));
52
+ }
53
+
54
+ public function testfilteronBothfeedAndGeneric() {
55
+ $query = new AfsQuery();
56
+ $query = $query->add_filter('foo', 'bar');
57
+ $query = $query->add_filter_on_feed('foo', array('barr'), 'feed');
58
+
59
+ $this->assertTrue($query->has_filter('foo', 'bar'));
60
+ $this->assertTrue($query->has_filter('foo', 'barr', 'feed'));
61
+ $this->assertEquals($query->get_filter_values('foo', 'feed'), array('barr'));
62
+ $this->assertEquals($query->get_filter_values('foo'), array('bar'));
63
+ }
64
+
65
+
66
  public function testAddFilterValue()
67
  {
68
  $query = new AfsQuery();
176
  } catch (Exception $e) {
177
  $this->fail('Exception raised: ' . $e);
178
  }
179
+
180
+ try {
181
+ $query->remove_filter('foo', 'bar', 'feed');
182
+ } catch (Exception $e) {
183
+ $this->fail('Exception raised: ' . $e);
184
+ }
185
  }
186
  public function testRemoveUnexistingFilterValue()
187
  {
192
  } catch (Exception $e) {
193
  $this->fail('Exception raised: ' . $e);
194
  }
195
+
196
+ $query = $query->add_filter('foo', 'baz', 'feed');
197
+ try {
198
+ $query->remove_filter('foo', 'bar', 'feed');
199
+ } catch (Exception $e) {
200
+ $this->fail('Exception raised: ' . $e);
201
+ }
202
  }
203
  public function testRemoveExistingFilterValue()
204
  {
205
  $query = new AfsQuery();
206
  $query = $query->add_filter('foo', 'bar');
207
+ $query = $query->add_filter('foo', 'bar', 'feed');
208
  $query = $query->remove_filter('foo', 'bar');
209
+ $query = $query->remove_filter('foo', 'bar', 'feed');
210
  $this->assertFalse($query->has_filter('foo', 'bar'));
211
+ $this->assertFalse($query->has_filter('foo', 'bar', 'feed'));
212
  }
213
 
214
  public function testGetListOfValuesForUnexistingFilter()
221
  }
222
  $this->fail('Getting values from unexisting filter should raise exception!');
223
  }
224
+
225
+ public function testGetListOfValuesForUnexistingFilterFeed()
226
+ {
227
+ $query = new AfsQuery();
228
+ try {
229
+ $values = $query->get_filter_values('foo', 'feed');
230
+ } catch (Exception $e) {
231
+ return;
232
+ }
233
+ $this->fail('Getting values from unexisting filter should raise exception!');
234
+ }
235
+
236
  public function testGetListOfFilterValues()
237
  {
238
  $query = new AfsQuery();
243
  $this->assertTrue(in_array('baz', $values));
244
  }
245
 
246
+
247
+
248
  public function testGetEmptyListOfFilters()
249
  {
250
  $query = new AfsQuery();
326
  $this->assertTrue(in_array('foo', $query->get_feeds()));
327
  $this->assertTrue(in_array('bar', $query->get_feeds()));
328
  }
329
+
330
+ public function testFilterOnFeedDoesntAddFeedOnquery() {
331
+ $query = new AfsQuery();
332
+ $query = $query->add_filter('FOO', 'bar', 'feed');
333
+ $this->assertFalse($query->has_feed());
334
+ }
335
+
336
  public function testResetFeedName()
337
  {
338
  $query = new AfsQuery();
466
  $this->assertTrue($query->has_sort('afs:relevance'));
467
  $this->assertEquals(AfsSortOrder::DESC, $query->get_sort_order('afs:relevance'));
468
  }
469
+
470
+ public function testsetSortOnFeed() {
471
+ $query = new AfsQuery();
472
+ $query = $query->set_sort('afs:relevance', AfsSortOrder::DESC, 'feed');
473
+ $this->assertFalse($query->has_sort());
474
+ $this->assertTrue($query->has_sort('afs:relevance', 'feed'));
475
+ $this->assertEquals(AfsSortOrder::DESC, $query->get_sort_order('afs:relevance', 'feed'));
476
+ }
477
+
478
  public function testResetSortOrder()
479
  {
480
  $query = new AfsQuery();
740
  $this->assertEquals($query->get_key(), 'test');
741
  }
742
 
743
+ public function testFilterFeedNotInParameterList() {
744
+ $query = new AfsQuery();
745
+ $query = $query->add_filter('foo', 'bar', 'Catalog');
746
+ $result = $query->get_parameters();
747
+ $this->assertFalse(in_array(array('Catalog'), $result));
748
+ }
749
+
750
  public function testCloneQuery()
751
  {
752
  $query = new AfsQuery();
820
  $query = $query->add_filter('fox', 'bat');
821
  $query = $query->add_filter('fox', 'bas');
822
 
823
+ $query = $query->add_filter_on_feed('foo', array('bar'), 'feed');
824
+ $query = $query->add_filter_on_feed('foo', array('baz'), 'feed');
825
+ $query = $query->add_filter_on_feed('fox', array('bat'), 'feed');
826
+ $query = $query->add_filter_on_feed('fox', array('bas'), 'feed');
827
+
828
  $query = $query->add_feed('feed');
829
  $query = $query->add_feed('food');
830
 
862
  $this->assertTrue(in_array('bat', $result['filter']['fox']));
863
  $this->assertTrue(in_array('bas', $result['filter']['fox']));
864
 
865
+ $this->assertTrue(array_key_exists('filter@feed', $result));
866
+ $this->assertTrue(array_key_exists('foo', $result['filter@feed']));
867
+ $this->assertTrue(in_array('bar', $result['filter@feed']['foo']));
868
+ $this->assertTrue(in_array('baz', $result['filter@feed']['foo']));
869
+ $this->assertTrue(array_key_exists('fox', $result['filter@feed']));
870
+ $this->assertTrue(in_array('bat', $result['filter@feed']['fox']));
871
+ $this->assertTrue(in_array('bas', $result['filter@feed']['fox']));
872
+
873
  $this->assertTrue(array_key_exists('feed', $result));
874
  $this->assertTrue(in_array('feed', $result['feed']));
875
  $this->assertTrue(in_array('food', $result['feed']));
921
  'query' => 'query',
922
  'filter' => array('foo' => array('bar', 'baz'),
923
  'fox' => array('bat', 'bas')),
924
+ 'filter@feed' => array('fooo' => array('bar', 'baz'),
925
+ 'foxx' => array('bat', 'bas')),
926
  'feed' => array('feed', 'food'),
927
  'replies' => 666,
928
  'lang' => 'en',
946
  $this->assertTrue(in_array('bat', $query->get_filter_values('fox')));
947
  $this->assertTrue(in_array('bas', $query->get_filter_values('fox')));
948
 
949
+ $this->assertTrue(in_array('fooo', $query->get_filters('feed')));
950
+ $this->assertTrue(in_array('bar', $query->get_filter_values('fooo', 'feed')));
951
+ $this->assertTrue(in_array('baz', $query->get_filter_values('fooo', 'feed')));
952
+ $this->assertTrue(in_array('foxx', $query->get_filters('feed')));
953
+ $this->assertTrue(in_array('bat', $query->get_filter_values('foxx', 'feed')));
954
+ $this->assertTrue(in_array('bas', $query->get_filter_values('foxx', 'feed')));
955
+
956
  $this->assertTrue($query->has_feed());
957
  $this->assertTrue(in_array('feed', $query->get_feeds()));
958
  $this->assertTrue(in_array('food', $query->get_feeds()));
1090
  $this->assertTrue($facet_mgr->has_facet('FOO'));
1091
  $facet = $facet_mgr->get_facet('FOO');
1092
  $this->assertTrue($facet->has_single_mode());
1093
+ $this->assertFalse($facet_mgr->is_sticky($facet));
1094
  }
1095
  public function testFacetsSingleValuedAsList()
1096
  {
1128
  $query = $query->set_facet_order(array('foo', 'bar'), AfsFacetOrder::STRICT);
1129
  $this->assertTrue($query->get_facet_manager()->is_facet_order_strict());
1130
  }
1131
+
1132
+ public function testFtsDefault()
1133
+ {
1134
+ $query = new AfsQuery();
1135
+ $query->set_fts_default(AfsFtsMode::MANDATORY);
1136
+ $parameters = $query->get_parameters();
1137
+ $this->assertEquals('mandatory', $parameters['ftsDefault']);
1138
+ $query->set_fts_default(AfsFtsMode::OPTIONAL);
1139
+ $parameters = $query->get_parameters();
1140
+ $this->assertEquals('optional', $parameters['ftsDefault']);
1141
+ try {
1142
+ $query->set_fts_default('InvalidValu3');
1143
+ $this->fail();
1144
+ } catch (InvalidArgumentException $e) {
1145
+ $this->assertTrue(true);
1146
+ }
1147
+ }
1148
+
1149
+ public function testSetClientData()
1150
+ {
1151
+ $query = new AfsQuery();
1152
+ $ids = array(1,2,3);
1153
+ $query->set_client_data($ids);
1154
+ $parameters = $query->get_parameters();
1155
+ $clientData = $parameters['clientData'];
1156
+ $this->assertEquals(3, count($clientData));
1157
+ foreach ($ids as $id) {
1158
+ $this->assertTrue(in_array($id, $clientData));
1159
+ }
1160
+ $query->set_client_data(4);
1161
+ $parameters = $query->get_parameters();
1162
+ $clientData = $parameters['clientData'];
1163
+ $this->assertEquals(1, count($clientData));
1164
+ $this->assertTrue(in_array(4, $clientData));
1165
+ }
1166
+
1167
+ public function testAddClientData()
1168
+ {
1169
+ $query = new AfsQuery();
1170
+ $ids = array(1,2,3);
1171
+ $id = 4;
1172
+ $query->add_client_data($id);
1173
+ $query->add_client_data($ids);
1174
+ $parameters = $query->get_parameters();
1175
+ $clientData = $parameters['clientData'];
1176
+ $this->assertEquals(4, count($clientData));
1177
+ for ($i=1 ; $i <= 4 ; $i++) {
1178
+ $this->assertTrue(in_array($i, $clientData));
1179
+ }
1180
+ }
1181
+
1182
+ public function testSetGeoDistFilterDefaultParameters() {
1183
+ $query = new AfsQuery();
1184
+
1185
+ // test default parameters
1186
+ $query = $query->set_geoDist_filter(45.5, 5.2, 1000);
1187
+ $functionFilter = PHPUnit_Framework_Assert::readAttribute($query, "nativeFunctionFilter");
1188
+ $expectedAdvancedFilter = array("geo:dist(45.5,5.2,geo:lat,geo:long)<1000");
1189
+ $this->assertTrue($expectedAdvancedFilter == $functionFilter);
1190
+ }
1191
+
1192
+ public function testSetGeoDistFilterFullParameters()
1193
+ {
1194
+ $query = new AfsQuery();
1195
+
1196
+ // test full parameters call
1197
+ $query = $query->set_geoDist_filter(45.5, 5.2, 1000, 'MyLat', 'MyLong');
1198
+ $functionFilter = PHPUnit_Framework_Assert::readAttribute($query, 'nativeFunctionFilter');
1199
+ $expectedNativeFunctionFilter = array("geo:dist(45.5,5.2,MyLat,MyLong)<1000");
1200
+ $this->assertTrue($expectedNativeFunctionFilter == $functionFilter);
1201
+ }
1202
+
1203
+ public function testSetGeoDistMustEraseExistingsOne() {
1204
+ $query = new AfsQuery();
1205
+
1206
+ $query = $query->set_geoDist_filter(45.5, 5.2, 1);
1207
+ $query = $query->set_geoDist_filter(43, 5.2, 2000);
1208
+
1209
+ $functionFilter = PHPUnit_Framework_Assert::readAttribute($query, 'nativeFunctionFilter');
1210
+ $expectedNativeFunctionFilter = "geo:dist(43,5.2,geo:lat,geo:long)<2000";
1211
+ $this->assertTrue(in_array($expectedNativeFunctionFilter, $functionFilter));
1212
+ }
1213
+
1214
+ public function testSetGeoDistMusntEraseOthersFilters()
1215
+ {
1216
+ $query = new AfsQuery();
1217
+
1218
+ $query = $query->set_advanced_filter(filter("FOO")->less->value(42));
1219
+ $query = $query->set_filter('foo', 'bar');
1220
+ $query = $query->set_geoDist_filter(43, 5.2, 2000);
1221
+
1222
+ $advancedFilter = PHPUnit_Framework_Assert::readAttribute($query, 'advancedFilter');
1223
+ $functionFilter = PHPUnit_Framework_Assert::readAttribute($query, 'nativeFunctionFilter');
1224
+ $expectedFunctionFilter = array("geo:dist(43,5.2,geo:lat,geo:long)<2000");
1225
+ $filter = PHPUnit_Framework_Assert::readAttribute($query, 'filter');
1226
+
1227
+ // check in query object
1228
+ $this->assertTrue(in_array('FOO<42', $advancedFilter));
1229
+
1230
+ $facet_id_found = false;
1231
+ $filter_foo = null;
1232
+ foreach ($filter as $f) {
1233
+ if ($f->get_facet_id() === 'foo') {
1234
+ $facet_id_found = true;
1235
+ $filter_foo = $f;
1236
+ break;
1237
+ }
1238
+ }
1239
+ $this->assertTrue($facet_id_found);
1240
+
1241
+ $this->assertTrue($filter_foo->get_values() == array('bar'));
1242
+ $this->assertTrue($expectedFunctionFilter == $functionFilter);
1243
+ }
1244
+
1245
+ public function testFeedContextualization() {
1246
+ $query = new AfsQuery();
1247
+
1248
+ $query = $query->set_filter_on_feed('foo', array('bar'), 'food');
1249
+ $query = $query->set_page(7, 'food');
1250
+ //$query = $query->set_count(10, 'food');
1251
+ $query = $query->set_query('blabla', 'food');
1252
+ $query = $query->set_replies(100, 'food');
1253
+ $query = $query->set_from(AfsOrigin::PRODUCT_DESCRIPTION, 'food');
1254
+ $query = $query->set_key('key1', 'food');
1255
+ $query = $query->set_sort('lang', AfsSortOrder::ASC, 'food');
1256
+
1257
+ $this->assertTrue($query->get_page('food') == 7);
1258
+ $this->assertTrue($query->get_page() == 1);
1259
+ //$this->assertTrue($query->get_count('food') == 10);
1260
+ //$this->assertFalse($query->has_count());
1261
+ $this->assertTrue($query->get_query('food') == 'blabla');
1262
+ $this->assertFalse($query->has_query());
1263
+ $this->assertTrue($query->get_replies('food') == 100);
1264
+ $this->assertTrue($query->get_replies() == 10);
1265
+ $this->assertTrue($query->get_from('food') == AfsOrigin::PRODUCT_DESCRIPTION);
1266
+ $this->assertTrue($query->get_key('food') == 'key1');
1267
+ $this->assertFalse($query->has_key());
1268
+ $this->assertTrue($query->has_sort('lang', 'food'));
1269
+ }
1270
  }
1271
 
1272
 
lib/antidot/AFS/SEARCH/TEST/replyHelperTest.php CHANGED
@@ -1,5 +1,31 @@
1
  <?php ob_start();
 
2
  require_once "AFS/SEARCH/afs_reply_helper.php";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
 
4
  class ReplyHelperTest extends PHPUnit_Framework_TestCase
5
  {
@@ -53,4 +79,185 @@ class ReplyHelperTest extends PHPUnit_Framework_TestCase
53
 
54
  $this->assertEquals('data 1', $helper->get_clientdata()->get_value('/clientdata/data/data1[2]'));
55
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
  }
1
  <?php ob_start();
2
+ require_once "AFS/SEARCH/afs_reply_helper_factory.php";
3
  require_once "AFS/SEARCH/afs_reply_helper.php";
4
+ require_once "AFS/SEARCH/afs_text_helper.php";
5
+
6
+ class TestTextVisitor implements AfsTextVisitorInterface {
7
+
8
+ /** @brief Visit @a AfsStringText instance.
9
+ * @param $afs_text [in] visited instance.
10
+ */
11
+ public function visit_AfsStringText(AfsStringText $afs_text)
12
+ {
13
+ }
14
+
15
+ /** @brief Visit @a AfsMatchText instance.
16
+ * @param $afs_text [in] visited instance.
17
+ */
18
+ public function visit_AfsMatchText(AfsMatchText $afs_text)
19
+ {
20
+ }
21
+
22
+ /** @brief Visit @a AfsTruncateText instance.
23
+ * @param $afs_text [in] visited instance.
24
+ */
25
+ public function visit_AfsTruncateText(AfsTruncateText $afs_text)
26
+ {
27
+ }
28
+ }
29
 
30
  class ReplyHelperTest extends PHPUnit_Framework_TestCase
31
  {
79
 
80
  $this->assertEquals('data 1', $helper->get_clientdata()->get_value('/clientdata/data/data1[2]'));
81
  }
82
+
83
+ public function testGetGeoDataSouldReturnNull () {
84
+ $reply = json_decode('{
85
+ "docId": 180,
86
+ "uri": "http://foo.bar.baz/14",
87
+ "title": [
88
+ {
89
+ "afs:t": "KwicString",
90
+ "text": "The title 14"
91
+ }
92
+ ]
93
+ }');
94
+ $helper = new AfsReplyHelper($reply);
95
+ $this->assertTrue($helper->get_geo_data() == null);
96
+ }
97
+
98
+ public function testGetGeoData() {
99
+ $reply = json_decode('{
100
+ "docId": 180,
101
+ "uri": "http://foo.bar.baz/14",
102
+ "title": [
103
+ {
104
+ "afs:t": "KwicString",
105
+ "text": "The title 14"
106
+ }
107
+ ],
108
+ "geo_reply_ext": [{
109
+
110
+ "point": {
111
+ "dist" : 0,
112
+ "lat" : 45,
113
+ "lon" : 5
114
+ }
115
+ }]
116
+
117
+ }');
118
+ $helper = new AfsReplyHelper($reply);
119
+ $geo_data = $helper->get_geo_data();
120
+
121
+ $expected_geo_data = new stdClass();
122
+ $expected_geo_data->dist = 0;
123
+ $expected_geo_data->lat = 45;
124
+ $expected_geo_data->lon = 5;
125
+ $this->assertTrue($geo_data[0]->point == $expected_geo_data);
126
+ }
127
+
128
+ public function testHasGeoDataShouldReturnTrue() {
129
+ $reply = json_decode('{
130
+ "docId": 180,
131
+ "uri": "http://foo.bar.baz/14",
132
+ "title": [
133
+ {
134
+ "afs:t": "KwicString",
135
+ "text": "The title 14"
136
+ }
137
+ ],
138
+ "geo_reply_ext": [{
139
+
140
+ "point": {
141
+ "dist" : 0,
142
+ "lat" : 45,
143
+ "lon" : 5
144
+ }
145
+ }]
146
+
147
+ }');
148
+
149
+ $helper = new AfsReplyHelper($reply);
150
+
151
+ $this->assertTrue($helper->has_geo_data());
152
+ }
153
+
154
+ public function testHasGeoDataShouldReturnFalse() {
155
+ $reply = json_decode('{
156
+ "docId": 180,
157
+ "uri": "http://foo.bar.baz/14",
158
+ "title": [
159
+ {
160
+ "afs:t": "KwicString",
161
+ "text": "The title 14"
162
+ }
163
+ ]
164
+ }');
165
+
166
+ $helper = new AfsReplyHelper($reply);
167
+
168
+ $this->assertTrue(! $helper->has_geo_data());
169
+ }
170
+
171
+ public function testReplyHelperFactoryOnRedirectionPromote() {
172
+ $clientData = '<afs:type xmlns:afs=\"http://ref.antidot.net/7.3/bo.xsd\">redirection</afs:type>';
173
+ $reply = json_decode('{
174
+ "docId": 180,
175
+ "uri": "http://foo.bar.baz/14",
176
+ "relevance" : {"rank" : 1},
177
+ "clientData": [
178
+ {
179
+ "contents": " ' . $clientData . '",
180
+ "id": "main",
181
+ "mimeType": "text/xml"
182
+ }
183
+ ]
184
+ }');
185
+
186
+ $text_visitor = new TestTextVisitor();
187
+ $factory = new AfsReplyHelperFactory($text_visitor);
188
+
189
+ $promote = $factory->create('Promote', $reply);
190
+ $this->assertTrue($promote instanceof AfsPromoteRedirectReplyHelper);
191
+ $this->assertEquals('http://foo.bar.baz/14', $promote->get_url());
192
+ }
193
+
194
+ public function testReplyHelperFactoryOnBannerPromote() {
195
+ $clientData = '<afs:type xmlns:afs=\"http://ref.antidot.net/7.3/bo.xsd\">banner</afs:type><afs:images xmlns:afs=\"http://ref.antidot.net/7.3/bo.xsd\"><afs:image><afs:url>http://url</afs:url><afs:imageUrl>http://image/url</afs:imageUrl></afs:image></afs:images>';
196
+ $reply = json_decode('{
197
+ "docId": 180,
198
+ "uri": "http://foo.bar.baz/14",
199
+ "relevance" : {"rank" : 1},
200
+ "clientData": [
201
+ {
202
+ "contents": " ' . $clientData . '",
203
+ "id": "main",
204
+ "mimeType": "text/xml"
205
+ }
206
+ ]
207
+ }');
208
+
209
+ $text_visitor = new TestTextVisitor();
210
+ $factory = new AfsReplyHelperFactory($text_visitor);
211
+
212
+ $promote = $factory->create('Promote', $reply);
213
+ $this->assertTrue($promote instanceof AfsPromoteBannerReplyHelper);
214
+ $this->assertEquals('http://url', $promote->get_url());
215
+ $this->assertEquals('http://image/url', $promote->get_image_url());
216
+ }
217
+
218
+ public function testReplyHelperFactoryOnDefaultPromote() {
219
+ $clientData = '<afs:type xmlns:afs=\"http://ref.antidot.net/7.3/bo.xsd\">default</afs:type><afs:customData xmlns:afs=\"http://ref.antidot.net/7.3/bo.xsd\"/>';
220
+ $reply = json_decode('{
221
+ "docId": 180,
222
+ "uri": "http://foo.bar.baz/14",
223
+ "relevance" : {"rank" : 1},
224
+ "clientData": [
225
+ {
226
+ "contents": " ' . $clientData . '",
227
+ "id": "main",
228
+ "mimeType": "text/xml"
229
+ }
230
+ ]
231
+ }');
232
+
233
+ $text_visitor = new TestTextVisitor();
234
+ $factory = new AfsReplyHelperFactory($text_visitor);
235
+
236
+ $promote = $factory->create('Promote', $reply);
237
+ $this->assertTrue($promote instanceof AfsPromoteReplyHelper);
238
+ }
239
+
240
+ /**
241
+ * @expectedException AfsUnknowPromoteTypeException
242
+ * @expectedExceptionMessage Unknow promote type: bidon
243
+ */
244
+ public function testUnknowPromoteType () {
245
+ $clientData = '<afs:type xmlns:afs=\"http://ref.antidot.net/7.3/bo.xsd\">bidon</afs:type><afs:customData xmlns:afs=\"http://ref.antidot.net/7.3/bo.xsd\"/>';
246
+ $reply = json_decode('{
247
+ "docId": 180,
248
+ "uri": "http://foo.bar.baz/14",
249
+ "relevance" : {"rank" : 1},
250
+ "clientData": [
251
+ {
252
+ "contents": " ' . $clientData . '",
253
+ "id": "main",
254
+ "mimeType": "text/xml"
255
+ }
256
+ ]
257
+ }');
258
+
259
+ $text_visitor = new TestTextVisitor();
260
+ $factory = new AfsReplyHelperFactory($text_visitor);
261
+ $factory->create('Promote', $reply);
262
+ }
263
  }
lib/antidot/AFS/SEARCH/TEST/replysetHelperTest.php CHANGED
@@ -222,8 +222,8 @@ class ReplysetHelperTest extends PHPUnit_Framework_TestCase
222
 
223
  $this->assertTrue($helper->has_pager());
224
  $pager = $helper->get_pager();
225
- $this->assertEquals($pager->get_next()->get_page(), '3');
226
- $this->assertEquals($pager->get_previous()->get_page(), '1');
227
  // and so on...
228
  }
229
 
@@ -448,7 +448,7 @@ class ReplysetHelperTest extends PHPUnit_Framework_TestCase
448
 
449
  $this->assertTrue($helper->has_pager());
450
  $pager = $helper->get_pager();
451
- $this->assertEquals('foo.php?replies=2&query=title&page=3', $pager->get_next());
452
  $this->assertEquals('foo.php?replies=2&query=title', $pager->get_previous());
453
  // and so on...
454
  }
@@ -675,7 +675,7 @@ class ReplysetHelperTest extends PHPUnit_Framework_TestCase
675
 
676
  $this->assertTrue($helper->has_pager());
677
  $pager = $helper->get_pager()->format();
678
- $this->assertEquals('foo.php?replies=2&query=title&page=3', $pager['pages']['next']);
679
  $this->assertEquals('foo.php?replies=2&query=title', $pager['pages']['previous']);
680
  // and so on...
681
  }
222
 
223
  $this->assertTrue($helper->has_pager());
224
  $pager = $helper->get_pager();
225
+ $this->assertEquals($pager->get_next()->get_page('Test'), '3');
226
+ $this->assertEquals($pager->get_previous()->get_page('Test'), '1');
227
  // and so on...
228
  }
229
 
448
 
449
  $this->assertTrue($helper->has_pager());
450
  $pager = $helper->get_pager();
451
+ $this->assertEquals('foo.php?replies=2&query=title&page@Test=3', $pager->get_next());
452
  $this->assertEquals('foo.php?replies=2&query=title', $pager->get_previous());
453
  // and so on...
454
  }
675
 
676
  $this->assertTrue($helper->has_pager());
677
  $pager = $helper->get_pager()->format();
678
+ $this->assertEquals('foo.php?replies=2&query=title&page@Test=3', $pager['pages']['next']);
679
  $this->assertEquals('foo.php?replies=2&query=title', $pager['pages']['previous']);
680
  // and so on...
681
  }
lib/antidot/AFS/SEARCH/TEST/responseHelperTest.php CHANGED
@@ -25,6 +25,7 @@ class ResponseHelperTest extends PHPUnit_Framework_TestCase
25
  $query = new AfsQuery();
26
  $response = new AfsResponseHelper($input, $query, $config);
27
  $this->assertFalse($response->has_replyset());
 
28
  $this->assertFalse($response->in_error());
29
  $this->assertFalse($response->has_spellcheck());
30
  $this->assertFalse($response->has_promote());
25
  $query = new AfsQuery();
26
  $response = new AfsResponseHelper($input, $query, $config);
27
  $this->assertFalse($response->has_replyset());
28
+ $this->assertFalse($response->has_replyset('Catalog'));
29
  $this->assertFalse($response->in_error());
30
  $this->assertFalse($response->has_spellcheck());
31
  $this->assertFalse($response->has_promote());
lib/antidot/AFS/SEARCH/TEST/searchQueryManagerTest.php CHANGED
@@ -32,6 +32,18 @@ class SearchQueryManagerTest extends PHPUnit_Framework_TestCase
32
  $this->qm = new AfsSearchQueryManager($this->connector, $this->config);
33
  }
34
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  private function checkOneFacetValue($facet_id, $facet_value, $operator='=')
36
  {
37
  $params = $this->connector->get_parameters();
@@ -330,4 +342,27 @@ class SearchQueryManagerTest extends PHPUnit_Framework_TestCase
330
  $this->assertFalse(strpos($url, $afs_log.'LOGGG') === False,
331
  'No afs:log LOGGG in URL: '.$url);
332
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
333
  }
32
  $this->qm = new AfsSearchQueryManager($this->connector, $this->config);
33
  }
34
 
35
+ private function checkfilterValues($values) {
36
+ $params = $this->connector->get_parameters();
37
+ foreach ($values as $value)
38
+ $this->assertTrue(in_array($value, $params['afs:filter']));
39
+ }
40
+
41
+ private function checkSortValues($values) {
42
+ $params = $this->connector->get_parameters();
43
+ foreach ($values as $value)
44
+ $this->assertTrue(in_array($value, $params['afs:sort']));
45
+ }
46
+
47
  private function checkOneFacetValue($facet_id, $facet_value, $operator='=')
48
  {
49
  $params = $this->connector->get_parameters();
342
  $this->assertFalse(strpos($url, $afs_log.'LOGGG') === False,
343
  'No afs:log LOGGG in URL: '.$url);
344
  }
345
+
346
+ public function testNativeFunctionDoesntOverrideFilters() {
347
+ $query = new AfsQuery();
348
+
349
+ $query = $query->set_filter('foo', 'bar');
350
+ $filter = filter('Foo')->less->value(42);
351
+ $query = $query->set_advanced_filter($filter);
352
+ $query = $query->set_geoDIst_filter(45, 5, 1000);
353
+
354
+ $this->qm->send($query);
355
+ $this->checkfilterValues(array('foo=bar', $filter->to_string(), 'geo:dist(45,5,geo:lat,geo:long)<1000'));
356
+ }
357
+
358
+ public function testNativeFunctionDoesntOverrideSort() {
359
+ $query = new AfsQuery();
360
+
361
+ $query = $query->set_sort('foo');
362
+ $query = $query->add_sort('bar');
363
+ $query = $query->set_geoDIst_sort(45, 5);
364
+
365
+ $this->qm->send($query);
366
+ $this->checkSortValues(array('foo,DESC', 'bar,DESC', 'geo:dist(45,5,geo:lat,geo:long),DESC'));
367
+ }
368
  }
lib/antidot/AFS/SEARCH/TEST/searchTest.php CHANGED
@@ -9,6 +9,7 @@ class SearchTest extends PHPUnit_Framework_TestCase
9
  {
10
  $search = new AfsSearch('127.0.0.1', 666);
11
 
 
12
  $service = $search->get_service();
13
  $this->assertEquals(666, $service->id);
14
  $this->assertEquals(AfsServiceStatus::STABLE, $service->status);
@@ -23,6 +24,17 @@ class SearchTest extends PHPUnit_Framework_TestCase
23
  $this->assertEquals(AfsHelperFormat::HELPERS, $config->get_helper_format());
24
  }
25
 
 
 
 
 
 
 
 
 
 
 
 
26
  public function testRetrieveSpecificParameters()
27
  {
28
  $search = new AfsSearch('127.0.0.2', 42, AfsServiceStatus::RC);
@@ -41,6 +53,18 @@ class SearchTest extends PHPUnit_Framework_TestCase
41
  $this->assertEquals(AfsHelperFormat::ARRAYS, $config->get_helper_format());
42
  }
43
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  public function testSetQuery()
45
  {
46
  $search = new AfsSearch('127.0.0.1', 666);
@@ -54,6 +78,29 @@ class SearchTest extends PHPUnit_Framework_TestCase
54
  $this->assertTrue(strpos($search->get_generated_url(), 'query=foo') !== False, 'URL does not contain query!');
55
  }
56
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
  //Ensure custom parameters are kept
58
  public function testKeepCustomParameters()
59
  {
9
  {
10
  $search = new AfsSearch('127.0.0.1', 666);
11
 
12
+
13
  $service = $search->get_service();
14
  $this->assertEquals(666, $service->id);
15
  $this->assertEquals(AfsServiceStatus::STABLE, $service->status);
24
  $this->assertEquals(AfsHelperFormat::HELPERS, $config->get_helper_format());
25
  }
26
 
27
+ public function testBuildFromUrl() {
28
+ $search = new AfsSearch('127.0.0.1', 666);
29
+
30
+ $_SERVER['QUERY_STRING'] = 'filter=key_val-k_v';
31
+ $_GET['filter'] = 'key_val-k_v';
32
+ $query = $search->build_query_from_url_parameters();
33
+
34
+ $this->assertTrue($query->has_filter('key', 'val'));
35
+ $this->assertTrue($query->has_filter('k', 'v'));
36
+ }
37
+
38
  public function testRetrieveSpecificParameters()
39
  {
40
  $search = new AfsSearch('127.0.0.2', 42, AfsServiceStatus::RC);
53
  $this->assertEquals(AfsHelperFormat::ARRAYS, $config->get_helper_format());
54
  }
55
 
56
+ public function testEncodedUrlRobustness() {
57
+ $_GET['query'] = 'perles';
58
+ $_GET['filter'] = 'marketing_"is|_promotional"-price|_eur_"[0 .. 1]"';
59
+
60
+ $search = new AfsSearch('127.0.0.2', 42, AfsServiceStatus::RC);
61
+ $query = $search->build_query_from_url_parameters();
62
+
63
+
64
+ $this->assertTrue($query->has_filter('marketing', "\"is_promotional\""));
65
+ $this->assertTrue($query->has_filter('price_eur', "\"[0 .. 1]\""));
66
+ }
67
+
68
  public function testSetQuery()
69
  {
70
  $search = new AfsSearch('127.0.0.1', 666);
78
  $this->assertTrue(strpos($search->get_generated_url(), 'query=foo') !== False, 'URL does not contain query!');
79
  }
80
 
81
+ public function testBuildQueryFromUrlParametersType() {
82
+ $search = new AfsSearch('127.0.0.1', 666);
83
+
84
+ $_GET['page'] = 10;
85
+ $_GET['replies'] = 100;
86
+ $query = $search->build_query_from_url_parameters();
87
+
88
+ $this->assertTrue(is_int($query->get_replies()));
89
+ $this->assertTrue(is_int($query->get_page()));
90
+ $this->assertEquals(10, $query->get_page());
91
+ $this->assertEquals(100, $query->get_replies());
92
+ }
93
+
94
+ public function testSetFeedFilter() {
95
+ $search = new AfsSearch('127.0.0.1', 666);
96
+ $query = new AfsQuery();
97
+ $query = $query->set_filter_on_feed('foo', array('bar'), 'feed');
98
+ $search->set_query($query);
99
+
100
+ $search->execute();
101
+ $this->assertTrue(strpos($search->get_generated_url(), 'filter%40feed=foo%3Dbar') !== False, 'URL does not contain query!');
102
+ }
103
+
104
  //Ensure custom parameters are kept
105
  public function testKeepCustomParameters()
106
  {
lib/antidot/AFS/SEARCH/afs_base_reply_helper.php CHANGED
@@ -82,7 +82,6 @@ class AfsBaseReplyHelper extends AfsHelperBase
82
  $text_mgr = new AfsTextManager($json_text);
83
  return $text_mgr->visit_text($this->visitor);
84
  }
85
-
86
  }
87
 
88
 
82
  $text_mgr = new AfsTextManager($json_text);
83
  return $text_mgr->visit_text($this->visitor);
84
  }
 
85
  }
86
 
87
 
lib/antidot/AFS/SEARCH/afs_client_data_helper.php CHANGED
@@ -3,6 +3,10 @@ require_once "AFS/SEARCH/afs_text_visitor.php";
3
  require_once "AFS/SEARCH/afs_client_data_exception.php";
4
  require_once "COMMON/afs_helper_base.php";
5
  require_once "COMMON/afs_tools.php";
 
 
 
 
6
 
7
 
8
  /** @brief Manage client data.
@@ -92,6 +96,7 @@ interface AfsClientDataHelperInterface
92
  * @return first matching client data with specified name as text.
93
  */
94
  public function get_value($name=null, $context=array(), $formatter=null);
 
95
  /** @brief Retrieves client data as array of texts.
96
  *
97
  * All client data or sub-tree can be retrieved depending on @a name
@@ -106,6 +111,22 @@ interface AfsClientDataHelperInterface
106
  */
107
  public function get_values($name=null, $context=array(), $formatter=null);
108
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
  /** @brief Retrieve client data's mime type.
110
  *
111
  * @return mime type of the client data.
@@ -169,7 +190,7 @@ class AfsXmlClientDataHelper extends AfsClientDataHelperBase implements AfsClien
169
  private $contents = null;
170
  private $doc = null;
171
  private $callbacks = array(); // callbacks activated on specific node name
172
- private static $afs_ns = 'http://ref.antidot.net/v7/afs#';
173
 
174
  /** @brief Construct new instance of XML helper.
175
  * @param $client_data [in] input data used to initialize the instance.
@@ -192,8 +213,9 @@ class AfsXmlClientDataHelper extends AfsClientDataHelperBase implements AfsClien
192
  } else {
193
  $this->contents = $client_data->contents;
194
  }
 
195
  $this->doc = new DOMDocument();
196
- $this->doc->loadXML($this->contents);
197
  }
198
 
199
  /** @brief Retrieves text from XML node.
@@ -201,7 +223,8 @@ class AfsXmlClientDataHelper extends AfsClientDataHelperBase implements AfsClien
201
  * @remark @c afs prefix should never be used in provided XPath.
202
  *
203
  * @param $path [in] XPath to apply (default=null, retrieve all content as
204
- * text).
 
205
  * @param $nsmap [in] prefix/uri mapping to use along with provided XPath.
206
  * @param $callbacks [in] list of callbacks to emphase text when highlight
207
  * of client data is activated or when client data text is truncated.
@@ -218,6 +241,7 @@ class AfsXmlClientDataHelper extends AfsClientDataHelperBase implements AfsClien
218
  if (is_null($path)) {
219
  return $this->contents;
220
  } else {
 
221
  $items = $this->apply_xpath($path, $nsmap);
222
  $named_callbacks = $this->update_callbacks(is_null($callbacks) ? array() : $callbacks);
223
  return DOMNodeHelper::get_text($items->item(0), $named_callbacks);
@@ -246,6 +270,7 @@ class AfsXmlClientDataHelper extends AfsClientDataHelperBase implements AfsClien
246
  if (is_null($path)) {
247
  return array($this->contents);
248
  } else {
 
249
  $items = $this->apply_xpath($path, $nsmap);
250
  $named_callbacks = $this->update_callbacks(is_null($callbacks) ? array() : $callbacks);
251
  $result = array();
@@ -256,6 +281,219 @@ class AfsXmlClientDataHelper extends AfsClientDataHelperBase implements AfsClien
256
  }
257
  }
258
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
259
  /** @internal
260
  * @brief Retrieves values at given XPath or fails.
261
  *
@@ -282,6 +520,7 @@ class AfsXmlClientDataHelper extends AfsClientDataHelperBase implements AfsClien
282
  } elseif ($result->length == 0) {
283
  throw new AfsNoResultException('No result available for: ' . $path);
284
  }
 
285
  return $result;
286
  }
287
 
@@ -341,56 +580,57 @@ class AfsJsonClientDataHelper extends AfsClientDataHelperBase implements AfsClie
341
  * @par Example with name=null:
342
  * Input JSON client data:
343
  * @verbatim
344
- {
345
- "clientData": [
346
- {
347
- "contents": { "data": [ "afs:t": "KwicString", "text": "some text" ] },
348
- "id": "data1",
349
- "mimeType": "application/json"
350
- }
351
- ]
352
- }
353
- @endverbatim
354
  * Call to <tt>get_text(null)</tt> will return
355
  * @verbatim {"data":["afs:t":"KwicString","text":"some text"]}@endverbatim.
356
  *
357
  * @par Example with name='data':
358
  * Same input JSON as previous example:
359
  * @verbatim
360
- {
361
- "clientData": [
362
- {
363
- "contents": { "data": [ "afs:t": "KwicString", "text": "some text" ] },
364
- "id": "data1",
365
- "mimeType": "application/json"
366
- }
367
- ]
368
- }
369
- @endverbatim
370
  * Call to <tt>get_text('data')</tt> will return
371
  * @verbatim some text @endverbatim.
372
  *
373
  * @par Example with name='':
374
  * Client data is a @em simple text:
375
  * @verbatim
376
- {
377
- "clientData": [
378
- {
379
- "contents": [ { "afs:t": "KwicString", "text": "some text" } ],
380
- "id": "data1",
381
- "mimeType": "application/json"
382
- }
383
- ]
384
- }
385
- @endverbatim
386
  * Call to <tt>get_text('')</tt> will return
387
  * @verbatim some text @endverbatim.
388
  */
389
- public function get_value($name=null, $unused=array(), $visitor=null)
390
  {
391
- return $this->get_values($name, $unused, $visitor);
392
  }
393
 
 
394
  /** @brief Same result as @a get_value method
395
  *
396
  * @param $name [in] name of the first element to retrieve (default=null,
@@ -404,7 +644,7 @@ class AfsJsonClientDataHelper extends AfsClientDataHelperBase implements AfsClie
404
  *
405
  * @return formatted text.
406
  *
407
- * @exception AfsNoResultException when required JSON element is not defined.
408
  */
409
  public function get_values($name=null, $unused=array(), $visitor=null)
410
  {
@@ -428,6 +668,47 @@ class AfsJsonClientDataHelper extends AfsClientDataHelperBase implements AfsClie
428
  }
429
  }
430
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
431
  /** @brief Retrieve client data's mime type.
432
  *
433
  * @return application/json mime type.
3
  require_once "AFS/SEARCH/afs_client_data_exception.php";
4
  require_once "COMMON/afs_helper_base.php";
5
  require_once "COMMON/afs_tools.php";
6
+ require_once "COMMON/lib/JsonPath/JsonStore.php";
7
+ require_once "COMMON/lib/JsonPath/JsonPath.php";
8
+
9
+ use Peekmo\JsonPath\JsonStore;
10
 
11
 
12
  /** @brief Manage client data.
96
  * @return first matching client data with specified name as text.
97
  */
98
  public function get_value($name=null, $context=array(), $formatter=null);
99
+
100
  /** @brief Retrieves client data as array of texts.
101
  *
102
  * All client data or sub-tree can be retrieved depending on @a name
111
  */
112
  public function get_values($name=null, $context=array(), $formatter=null);
113
 
114
+ /**
115
+ * @brief Retrieves full client data node (value and attributes)
116
+ * @param $name [in] node name to be extracted
117
+ * @param $context [in] context used for looking for node with specified name.
118
+ * @return first occurrence of node as array
119
+ */
120
+ public function get_node($name=null, $context=array());
121
+
122
+ /**
123
+ * @brief Retrieves full client data nodes (value and attributes)
124
+ * @param $name [in] node name to be extracted
125
+ * @param $context [in] context used for looking for node with specified name.
126
+ * @return all occurrences as array
127
+ */
128
+ public function get_nodes($name=null, $context=array());
129
+
130
  /** @brief Retrieve client data's mime type.
131
  *
132
  * @return mime type of the client data.
190
  private $contents = null;
191
  private $doc = null;
192
  private $callbacks = array(); // callbacks activated on specific node name
193
+ public static $afs_ns = 'http://ref.antidot.net/v7/afs#';
194
 
195
  /** @brief Construct new instance of XML helper.
196
  * @param $client_data [in] input data used to initialize the instance.
213
  } else {
214
  $this->contents = $client_data->contents;
215
  }
216
+
217
  $this->doc = new DOMDocument();
218
+ $this->doc->loadXML($this->contents, LIBXML_NOBLANKS);
219
  }
220
 
221
  /** @brief Retrieves text from XML node.
223
  * @remark @c afs prefix should never be used in provided XPath.
224
  *
225
  * @param $path [in] XPath to apply (default=null, retrieve all content as
226
+ * text). Has client data is override by the clientData node, all XPaths
227
+ * should begin with '/clientData/...'
228
  * @param $nsmap [in] prefix/uri mapping to use along with provided XPath.
229
  * @param $callbacks [in] list of callbacks to emphase text when highlight
230
  * of client data is activated or when client data text is truncated.
241
  if (is_null($path)) {
242
  return $this->contents;
243
  } else {
244
+
245
  $items = $this->apply_xpath($path, $nsmap);
246
  $named_callbacks = $this->update_callbacks(is_null($callbacks) ? array() : $callbacks);
247
  return DOMNodeHelper::get_text($items->item(0), $named_callbacks);
270
  if (is_null($path)) {
271
  return array($this->contents);
272
  } else {
273
+
274
  $items = $this->apply_xpath($path, $nsmap);
275
  $named_callbacks = $this->update_callbacks(is_null($callbacks) ? array() : $callbacks);
276
  $result = array();
281
  }
282
  }
283
 
284
+ /**
285
+ * @brief Retrieves full client data node (value and attributes)
286
+ * @param $xpath [in] node name to be extracted
287
+ * @param $nsmap [in] namespace used for looking for node with specified name.
288
+ * @return first occurrence of node as array
289
+ * @throws AfsNoResultException
290
+ *
291
+ * @par Usage example:
292
+ * Input XML client data:
293
+ * @verbatim
294
+ * <clientData>
295
+ * <data1 attr='foo'>value1</data1>
296
+ * <data2><k>v</k></data2>
297
+ * </clientData>
298
+ * @endverbatim
299
+ *
300
+ * Call to get_node() will return
301
+ * @verbatim
302
+ array (
303
+ [clientData] => Array
304
+ (
305
+ [data1] => Array
306
+ (
307
+ [attributes] => Array
308
+ (
309
+ [attr] => foo
310
+ )
311
+
312
+ [0] => value1
313
+ )
314
+
315
+ [data2] => Array
316
+ (
317
+ [data1] => value2
318
+ )
319
+
320
+ )
321
+
322
+ )
323
+ @endverbatim
324
+ *
325
+ * Call to get_node('/clientData/data1') will return
326
+ * @verbatim
327
+ array (
328
+ [data1] => Array
329
+ (
330
+ [attributes] => Array
331
+ (
332
+ [attr] => foo
333
+ )
334
+
335
+ [0] => value1
336
+ )
337
+ )
338
+ @endverbatim
339
+ *
340
+ * Call to get_node('//data1/\@attr') will return
341
+ * @verbatim
342
+ Array
343
+ (
344
+ [attr] => foo
345
+ )
346
+ @endverbatim
347
+ */
348
+ public function get_node($xpath=null, $context=array()) {
349
+ $nodes = $this->get_nodes($xpath, $context);
350
+
351
+ if (is_array($nodes) && ! empty($nodes)){
352
+ return $nodes[0];
353
+ } else {
354
+ throw new AfsNoResultException($xpath . ' not found in current client data');
355
+ }
356
+ }
357
+
358
+ /**
359
+ * @brief Retrieves full client data nodes (value and attributes)
360
+ * @param $name [in] node name to be extracted
361
+ * @param $nsmap [in] namespace used for looking for node with specified name.
362
+ * @return all occurrences as array
363
+ * @throws AfsNoResultException
364
+ *
365
+ * @par Usage example:
366
+ * Input XML client data:
367
+ * @verbatim
368
+ * <clientData>
369
+ * <data1 attr='foo'>value1</data1>
370
+ * <data2><data1>value2</data1></data2>
371
+ * </clientData>
372
+ * @endverbatim
373
+ *
374
+ * Call to get_nodes() will return
375
+ * @verbatim
376
+ array
377
+ (
378
+ [0] => Array
379
+ (
380
+ [clientData] => Array
381
+ (
382
+ [data1] => Array
383
+ (
384
+ [attributes] => Array
385
+ (
386
+ [attr] => foo
387
+ )
388
+
389
+ [0] => value1
390
+ )
391
+
392
+ [data2] => Array
393
+ (
394
+ [data1] => value2
395
+ )
396
+
397
+ )
398
+
399
+ )
400
+
401
+ )
402
+ @endverbatim
403
+ *
404
+ * Call to get_nodes('//data1') will return
405
+ * @verbatim
406
+ array (
407
+ array (
408
+ [data1] => Array
409
+ (
410
+ [attributes] => Array
411
+ (
412
+ [attr] => foo
413
+ )
414
+ [0] => value1
415
+ )
416
+ )
417
+ array (
418
+ [data1] => value2
419
+ )
420
+ )
421
+
422
+ @endverbatim
423
+ *
424
+ * Call to get_nodes('//data1/@attr') will return
425
+ * @verbatim
426
+ Array
427
+ (
428
+ [attr] => foo
429
+ )
430
+ @endverbatim
431
+ */
432
+ public function get_nodes($xpath=null, $nsmap=array())
433
+ {
434
+ if (is_null($xpath) || $xpath === "") {
435
+ $xpath = "/";
436
+ }
437
+
438
+ $items = $this->apply_xpath($xpath, $nsmap);
439
+ if (empty($items)) {
440
+ throw new AfsNoResultException($xpath . ' not found in current client data');
441
+ } else {
442
+ $result = array();
443
+ foreach ($items as $item) {
444
+ if ($item instanceof DOMDocument) {
445
+ $item = $item->documentElement;
446
+ }
447
+ $result[] = $this->nodeToArray($this->doc, $item);
448
+ }
449
+ return $result;
450
+ }
451
+ }
452
+
453
+ /**
454
+ * @internal
455
+ * Returns an array representation of a DOMNode
456
+ * Note, make sure to use the LIBXML_NOBLANKS flag when loading XML into the DOMDocument
457
+ * @param DOMDocument $dom
458
+ * @param DOMNode $node
459
+ * @return array
460
+ */
461
+ private function nodeToArray( $dom, $node) {
462
+ if(!is_a( $dom, 'DOMDocument' ) || !is_a( $node, 'DOMNode' )) {
463
+ return false;
464
+ }
465
+ $array = false;
466
+ $attributes = array();
467
+
468
+ if( XML_TEXT_NODE == $node->nodeType ) {
469
+ return $node->nodeValue;
470
+ } elseif (XML_ATTRIBUTE_NODE == $node->nodeType) {
471
+ $array[$node->localName] = $node->nodeValue;
472
+ return $array;
473
+ }
474
+
475
+
476
+ if ($node->firstChild->nodeType == XML_TEXT_NODE) {
477
+ foreach ($node->attributes as $attr) {
478
+ $attributes[$attr->localName] = $attr->nodeValue;
479
+ }
480
+ if (! empty($attributes)) {
481
+ $array[$node->localName]['attributes'] = $attributes;
482
+ $array[$node->localName][] = $node->firstChild->nodeValue;
483
+ } else {
484
+ $array[$node->localName] = $node->firstChild->nodeValue;
485
+ }
486
+ } else {
487
+ $array[$node->localName] = array();
488
+ foreach ($node->childNodes as $childNode) {
489
+ if (false !== ($a = self::nodeToArray($dom, $childNode))) {
490
+ $array[$node->localName] = $array[$node->localName] + $a;
491
+ }
492
+ }
493
+ }
494
+ return $array;
495
+ }
496
+
497
  /** @internal
498
  * @brief Retrieves values at given XPath or fails.
499
  *
520
  } elseif ($result->length == 0) {
521
  throw new AfsNoResultException('No result available for: ' . $path);
522
  }
523
+
524
  return $result;
525
  }
526
 
580
  * @par Example with name=null:
581
  * Input JSON client data:
582
  * @verbatim
583
+ {
584
+ "clientData": [
585
+ {
586
+ "contents": { "data": [ "afs:t": "KwicString", "text": "some text" ] },
587
+ "id": "data1",
588
+ "mimeType": "application/json"
589
+ }
590
+ ]
591
+ }
592
+ @endverbatim
593
  * Call to <tt>get_text(null)</tt> will return
594
  * @verbatim {"data":["afs:t":"KwicString","text":"some text"]}@endverbatim.
595
  *
596
  * @par Example with name='data':
597
  * Same input JSON as previous example:
598
  * @verbatim
599
+ {
600
+ "clientData": [
601
+ {
602
+ "contents": { "data": [ "afs:t": "KwicString", "text": "some text" ] },
603
+ "id": "data1",
604
+ "mimeType": "application/json"
605
+ }
606
+ ]
607
+ }
608
+ @endverbatim
609
  * Call to <tt>get_text('data')</tt> will return
610
  * @verbatim some text @endverbatim.
611
  *
612
  * @par Example with name='':
613
  * Client data is a @em simple text:
614
  * @verbatim
615
+ * {
616
+ "clientData": [
617
+ {
618
+ "contents": [ { "afs:t": "KwicString", "text": "some text" } ],
619
+ "id": "data1",
620
+ "mimeType": "application/json"
621
+ }
622
+ ]
623
+ }
624
+ @endverbatim
625
  * Call to <tt>get_text('')</tt> will return
626
  * @verbatim some text @endverbatim.
627
  */
628
+ public function get_value($path=null, $unused=array(), $visitor=null)
629
  {
630
+ return $this->get_values($path, $unused, $visitor);
631
  }
632
 
633
+
634
  /** @brief Same result as @a get_value method
635
  *
636
  * @param $name [in] name of the first element to retrieve (default=null,
644
  *
645
  * @return formatted text.
646
  *
647
+ * @throws AfsNoResultException when required JSON element is not defined.
648
  */
649
  public function get_values($name=null, $unused=array(), $visitor=null)
650
  {
668
  }
669
  }
670
 
671
+ /**
672
+ * @brief Retrieves full client data node (not only text)
673
+ * @param $jpath [in] node name to be extracted
674
+ * @param $context [in] context used for looking for node with specified name.
675
+ * @return all matching nodes as array (each node format like json_decode in array mode)
676
+ * @throws AfsNoResultException
677
+ */
678
+ public function get_nodes($jpath=null, $unused=array()) {
679
+ if (is_null($jpath) || $jpath === "") {
680
+ // return json as array
681
+ return array(json_decode(json_encode($this->client_data->contents), true));
682
+ }
683
+
684
+ $store = new JsonStore($this->client_data->contents);
685
+ $result = $store->get($jpath, false);
686
+
687
+ if (! empty($result)) {
688
+ return $result;
689
+ } else {
690
+ throw new AfsNoResultException();
691
+ }
692
+ }
693
+
694
+ /**
695
+ * @brief Retrieves full client data node (not only text)
696
+ * @param $jpath [in] node name to be extracted
697
+ * @param $context [in] context used for looking for node with specified name.
698
+ * @return first occurrence of node as array (node format like json_decode in array mode)
699
+ * @throws AfsNoResultException
700
+ */
701
+ public function get_node($jpath=null, $unused=array())
702
+ {
703
+ $nodes = $this->get_nodes($jpath, $unused);
704
+
705
+ if (is_array($nodes) && ! empty($nodes)) {
706
+ return $nodes[0];
707
+ } else {
708
+ throw new AfsNoResultException('No result for: ' . $jpath);
709
+ }
710
+ }
711
+
712
  /** @brief Retrieve client data's mime type.
713
  *
714
  * @return application/json mime type.
lib/antidot/AFS/SEARCH/afs_cluster_parameter.php ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Created by PhpStorm.
4
+ * User: ct
5
+ * Date: 2/9/15
6
+ * Time: 5:47 PM
7
+ */
8
+
9
+ require_once 'AFS/afs_single_value_parameter.php';
10
+
11
+ class AfsClusterParameter extends AfsSingleValueParameter {
12
+ protected $facet_id;
13
+
14
+ public function __construct($facetId, $value, $feed=null) {
15
+ parent::__construct('cluster', $value, $feed);
16
+ $this->facet_id = $facetId;
17
+ }
18
+
19
+ public function get_facet_id() {
20
+ return $this->facet_id;
21
+ }
22
+
23
+ public function format () {
24
+ return $this->facet_id . ',' . $this->value;
25
+ }
26
+ }
lib/antidot/AFS/SEARCH/afs_facet.php CHANGED
@@ -14,6 +14,7 @@ class AfsFacet
14
  private $layout = null;
15
  private $mode = null;
16
  private $combination = null;
 
17
 
18
  /** @brief Construct new facet with specified parameters.
19
  *
@@ -28,17 +29,55 @@ class AfsFacet
28
  * (default: UNSPECIFIED_MODE).
29
  *
30
  * @exception InvalidArgumentException invalid parameter value provided for
31
- * @a type, @a layout or @a mode parameter.
32
  */
33
  public function __construct($id, $type=AfsFacetType::UNKNOWN_TYPE,
34
  $layout=AfsFacetLayout::TREE, $mode=AfsFacetMode::UNSPECIFIED_MODE)
35
  {
 
36
  $this->set_type($type);
37
  $this->id = $id;
38
  $this->layout = $layout;
39
  $this->set_mode($mode);
40
  }
41
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
  /** @brief Retrieves facet id.
43
  * @return facet id.
44
  */
@@ -81,7 +120,7 @@ class AfsFacet
81
  if (AfsFacetMode::SINGLE_MODE == $mode
82
  || AfsFacetMode::OR_MODE == $mode) {
83
  $this->combination = 'or';
84
- } elseif (AfsFacetMode::AND_MODE == $mode) {
85
  $this->combination = 'and';
86
  }
87
  }
@@ -114,6 +153,11 @@ class AfsFacet
114
  return $this->get_mode() == AfsFacetMode::AND_MODE;
115
  }
116
 
 
 
 
 
 
117
  /** @brief Checks whether provided facet is similar to current instance.
118
  *
119
  * Two instances are considered similar when following values are equals:
14
  private $layout = null;
15
  private $mode = null;
16
  private $combination = null;
17
+ private $values_sort_order = null;
18
 
19
  /** @brief Construct new facet with specified parameters.
20
  *
29
  * (default: UNSPECIFIED_MODE).
30
  *
31
  * @exception InvalidArgumentException invalid parameter value provided for
32
+ * @a id, @a type, @a layout or @a mode parameter.
33
  */
34
  public function __construct($id, $type=AfsFacetType::UNKNOWN_TYPE,
35
  $layout=AfsFacetLayout::TREE, $mode=AfsFacetMode::UNSPECIFIED_MODE)
36
  {
37
+ $this->validate_id($id);
38
  $this->set_type($type);
39
  $this->id = $id;
40
  $this->layout = $layout;
41
  $this->set_mode($mode);
42
  }
43
 
44
+ /**
45
+ * @brief set values sort order for this facet
46
+ *
47
+ * AFS search default sort for facet values is alphanumeric. This method
48
+ * allows to change this behaviour.
49
+ *
50
+ * @param $mode [in] the mode to use: see AfsFacetValuesSortMode
51
+ * @param $sort [in] the sort to use: see AfsSortOrder
52
+ */
53
+ public function set_values_sort_order($mode, $sort) {
54
+ $this->values_sort_order = new AfsFacetValuesSortOrder($mode, $sort);
55
+ }
56
+
57
+ /**
58
+ * @brief get current values sort order for this facet
59
+ * @return AfsFacetValuesSortOrder or null if sort order not specified
60
+ */
61
+ public function get_values_sort_order() {
62
+ return $this->values_sort_order;
63
+ }
64
+
65
+ /** @brief Validates facet identifier against official regex.
66
+ * @param $id [in] identifier to validate.
67
+ * @exception InvalidArgumentException when identifier doesn't validate.
68
+ * @exception Exception when bad internal error occures.
69
+ */
70
+ private function validate_id($id)
71
+ {
72
+ $id_pattern = '/^[a-zA-Z][a-zA-Z0-9_:]*$/';
73
+ $result = preg_match($id_pattern, $id);
74
+ if (0 == $result) {
75
+ throw new InvalidArgumentException('Provided facet id(' . $id . ') doesn\'t conform pattern: ' . $id_pattern);
76
+ } elseif (FALSE === $result) {
77
+ throw new Exception('Please contact Antidot support for this PHP API!');
78
+ }
79
+ }
80
+
81
  /** @brief Retrieves facet id.
82
  * @return facet id.
83
  */
120
  if (AfsFacetMode::SINGLE_MODE == $mode
121
  || AfsFacetMode::OR_MODE == $mode) {
122
  $this->combination = 'or';
123
+ } elseif (AfsFacetMode::AND_MODE == $mode || AfsFacetMode::STICKY_AND_MODE == $mode) {
124
  $this->combination = 'and';
125
  }
126
  }
153
  return $this->get_mode() == AfsFacetMode::AND_MODE;
154
  }
155
 
156
+ public function has_sticky_and_mode()
157
+ {
158
+ return $this->get_mode() == AfsFacetMode::STICKY_AND_MODE;
159
+ }
160
+
161
  /** @brief Checks whether provided facet is similar to current instance.
162
  *
163
  * Two instances are considered similar when following values are equals:
lib/antidot/AFS/SEARCH/afs_facet_helper.php CHANGED
@@ -11,7 +11,8 @@ function is_not_null($value) {
11
  class AfsFacetHelper extends AfsHelperBase
12
  {
13
  private $id = null;
14
- private $label = null;
 
15
  private $layout = null;
16
  private $type = null;
17
  private $sticky = null;
@@ -23,19 +24,20 @@ class AfsFacetHelper extends AfsHelperBase
23
  * @param $query [in] @a AfsQuery which has produced current reply.
24
  * @param $config [in] helper configuration object.
25
  */
26
- public function __construct($facet, AfsQuery $query, AfsHelperConfiguration $config)
27
  {
28
  $this->id = $facet->id;
29
- if (property_exists($facet, 'labels') && ! empty($facet->labels)
30
- && property_exists($facet->labels[0], 'label')) {
31
- $this->label = $facet->labels[0]->label;
32
- } else {
33
- $this->label = $this->id;
34
  }
 
35
  $this->layout = $facet->layout;
36
  $this->type = $facet->type;
37
  if (property_exists($facet, 'sticky')
38
- && 0 == strcmp('true', $facet->sticky)) {
39
  $this->sticky = true;
40
  } else {
41
  $this->sticky = false;
@@ -43,7 +45,7 @@ class AfsFacetHelper extends AfsHelperBase
43
  $facet_manager = $query->get_facet_manager();
44
  $facet_manager->check_or_add_facet(new AfsFacet($this->id, $this->type, $this->layout));
45
  $builder = new AfsFacetElementBuilder($facet_manager, $query);
46
- $this->elements = $builder->create_elements($this->id, $facet, $config);
47
  }
48
 
49
  /** @brief Retrieve facet label.
@@ -55,7 +57,44 @@ class AfsFacetHelper extends AfsHelperBase
55
  */
56
  public function get_label()
57
  {
58
- return $this->label;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
  }
60
 
61
  /** @brief Retrieves facet id.
@@ -116,7 +155,7 @@ class AfsFacetHelper extends AfsHelperBase
116
  public function format()
117
  {
118
  return array('label' => $this->get_label(),
119
- 'values' => $this->get_elements());
120
  }
121
 
122
  }
@@ -197,7 +236,7 @@ class AfsFacetValueHelper extends AfsHelperBase
197
  * @li @c label: label of the facet value,
198
  * @li @c key: key of the facet value,
199
  * @li @c count: number of element of the facet value,
200
- * @li @c active: state of the facet value: true when this facet value is
201
  * used in current query, false otherwise,
202
  * @li @c query: query associated to the facet value (see @a query property
203
  * for more details),
@@ -207,7 +246,7 @@ class AfsFacetValueHelper extends AfsHelperBase
207
  * @li @c meta: key-value pairs of meta data identifiers and values.
208
  *
209
  * @remark: When helpers are used to create such facet value, if @a link is
210
- * generated from @a query, then the query is no more necessary and not
211
  * provided. So one of @c query and @c link is null.
212
  *
213
  * @return array filled with key and values.
@@ -256,11 +295,11 @@ class AfsFacetElementBuilder
256
  * @return list of facet elements (see @ AfsFacetValueHelper).
257
  */
258
  public function create_elements($facet_id, $facet_element,
259
- AfsHelperConfiguration $config)
260
  {
261
  $formatter = AfsFacetHelperRetriever::get_formatter($facet_id, $this->query);
262
  return $this->create_elements_recursively($facet_id, $facet_element,
263
- $formatter, $config);
264
  }
265
 
266
  /** @internal
@@ -275,7 +314,7 @@ class AfsFacetElementBuilder
275
  * @return list of facet elements (see @ AfsFacetValueHelper).
276
  */
277
  private function create_elements_recursively($facet_id, $facet_element,
278
- AfsFacetValueIdFormatter $formatter, AfsHelperConfiguration $config)
279
  {
280
  $elements = array();
281
 
@@ -290,22 +329,27 @@ class AfsFacetElementBuilder
290
  $children = array();
291
  if (property_exists($elem, 'node')) {
292
  $children = $this->create_elements_recursively($facet_id,
293
- $elem, $formatter, $config);
294
  }
295
 
296
  $value_id = $formatter->format($elem->key);
297
  $label = $this->extract_label($elem);
298
  $meta = $this->extract_meta($elem);
299
- $active = $this->query->has_filter($facet_id, $value_id);
300
- $query = $this->generate_query($facet_id, $value_id, $active);
 
 
 
 
 
301
  if ($config->has_query_coder()) {
302
  $link = $config->get_query_coder()->generate_link($query);
303
- $query = null; // we don't need it anymore
304
  } else {
305
  $link = null;
306
  }
307
  $elements[] = new AfsFacetValueHelper($label, $value_id, $elem->items,
308
- $meta, $active, $query, $link, $children);
309
 
310
  }
311
  return $elements;
@@ -331,21 +375,32 @@ class AfsFacetElementBuilder
331
  return $result;
332
  }
333
 
334
- private function generate_query($facet_id, $value_id, $active)
335
  {
336
  $result = null;
337
  $facet = $this->facet_mgr->get_facet($facet_id);
 
338
  if ($active) {
339
- $result = $this->query->remove_filter($facet_id, $value_id);
 
 
 
 
340
  } else {
341
  if ($facet->has_single_mode()) {
342
- $result = $this->query->set_filter($facet_id, $value_id);
 
 
 
 
343
  } else {
344
- $result = $this->query->add_filter($facet_id, $value_id);
 
 
 
 
345
  }
346
  }
347
  return $result;
348
  }
349
  }
350
-
351
-
11
  class AfsFacetHelper extends AfsHelperBase
12
  {
13
  private $id = null;
14
+ private $labels = null;
15
+ private $tags = null;
16
  private $layout = null;
17
  private $type = null;
18
  private $sticky = null;
24
  * @param $query [in] @a AfsQuery which has produced current reply.
25
  * @param $config [in] helper configuration object.
26
  */
27
+ public function __construct($facet, AfsQuery $query, AfsHelperConfiguration $config, $feed=null)
28
  {
29
  $this->id = $facet->id;
30
+ if (property_exists($facet, 'labels') && ! empty($facet->labels)) {
31
+ $this->labels = $facet->labels;
32
+ }
33
+ if (property_exists($facet, 'tags')) {
34
+ $this->tags = $facet->tags;
35
  }
36
+
37
  $this->layout = $facet->layout;
38
  $this->type = $facet->type;
39
  if (property_exists($facet, 'sticky')
40
+ && 0 == strcmp('true', $facet->sticky)) {
41
  $this->sticky = true;
42
  } else {
43
  $this->sticky = false;
45
  $facet_manager = $query->get_facet_manager();
46
  $facet_manager->check_or_add_facet(new AfsFacet($this->id, $this->type, $this->layout));
47
  $builder = new AfsFacetElementBuilder($facet_manager, $query);
48
+ $this->elements = $builder->create_elements($this->id, $facet, $config, $feed);
49
  }
50
 
51
  /** @brief Retrieve facet label.
57
  */
58
  public function get_label()
59
  {
60
+ if (!is_null($this->labels)) {
61
+ return $this->labels[0]->label;
62
+ } else {
63
+ return $this->id;
64
+ }
65
+ }
66
+
67
+ /** @brief Retrieve all facet labels
68
+ *
69
+ * @return labels as a string array
70
+ */
71
+ public function get_labels() {
72
+ $labels = array();
73
+ if (!is_null($this->labels)) {
74
+ foreach ($this->labels as $label) {
75
+ if (property_exists($label, "lang")) {
76
+ $labels[strtolower($label->lang)] = ($label->label);
77
+ } else {
78
+ $labels[] = ($label->label);
79
+ }
80
+ }
81
+ }
82
+ else {
83
+ $labels[] = $this->id;
84
+ }
85
+ return $labels;
86
+ }
87
+
88
+ /** @brief Retrieve current facet tags
89
+ *
90
+ * @return tags as a string array or empty array if current facet have no tags
91
+ */
92
+ public function get_tags() {
93
+ if (! is_null($this->tags)) {
94
+ return explode(' ', $this->tags);
95
+ }
96
+
97
+ return array();
98
  }
99
 
100
  /** @brief Retrieves facet id.
155
  public function format()
156
  {
157
  return array('label' => $this->get_label(),
158
+ 'values' => $this->get_elements());
159
  }
160
 
161
  }
236
  * @li @c label: label of the facet value,
237
  * @li @c key: key of the facet value,
238
  * @li @c count: number of element of the facet value,
239
+ * @li @c active: state of the facet value: true when this facet value is
240
  * used in current query, false otherwise,
241
  * @li @c query: query associated to the facet value (see @a query property
242
  * for more details),
246
  * @li @c meta: key-value pairs of meta data identifiers and values.
247
  *
248
  * @remark: When helpers are used to create such facet value, if @a link is
249
+ * generated from @a query, then the query is no more necessary and not
250
  * provided. So one of @c query and @c link is null.
251
  *
252
  * @return array filled with key and values.
295
  * @return list of facet elements (see @ AfsFacetValueHelper).
296
  */
297
  public function create_elements($facet_id, $facet_element,
298
+ AfsHelperConfiguration $config, $feed=null)
299
  {
300
  $formatter = AfsFacetHelperRetriever::get_formatter($facet_id, $this->query);
301
  return $this->create_elements_recursively($facet_id, $facet_element,
302
+ $formatter, $config, $feed);
303
  }
304
 
305
  /** @internal
314
  * @return list of facet elements (see @ AfsFacetValueHelper).
315
  */
316
  private function create_elements_recursively($facet_id, $facet_element,
317
+ AfsFacetValueIdFormatter $formatter, AfsHelperConfiguration $config, $feed)
318
  {
319
  $elements = array();
320
 
329
  $children = array();
330
  if (property_exists($elem, 'node')) {
331
  $children = $this->create_elements_recursively($facet_id,
332
+ $elem, $formatter, $config, $feed);
333
  }
334
 
335
  $value_id = $formatter->format($elem->key);
336
  $label = $this->extract_label($elem);
337
  $meta = $this->extract_meta($elem);
338
+
339
+ $active = ($this->query->has_filter($facet_id, $value_id)) ||
340
+ $this->query->has_filter($facet_id, $value_id, $feed);
341
+
342
+ $feed = (! $this->query->has_filter($facet_id, $value_id, $feed)) ? null : $feed;
343
+
344
+ $query = $this->generate_query($facet_id, $value_id, $active, $feed);
345
  if ($config->has_query_coder()) {
346
  $link = $config->get_query_coder()->generate_link($query);
347
+ //$query = null; // we don't need it anymore
348
  } else {
349
  $link = null;
350
  }
351
  $elements[] = new AfsFacetValueHelper($label, $value_id, $elem->items,
352
+ $meta, $active, $query, $link, $children);
353
 
354
  }
355
  return $elements;
375
  return $result;
376
  }
377
 
378
+ private function generate_query($facet_id, $value_id, $active, $feed=null)
379
  {
380
  $result = null;
381
  $facet = $this->facet_mgr->get_facet($facet_id);
382
+
383
  if ($active) {
384
+ if (! is_null($feed)) {
385
+ $result = $this->query->remove_filter_on_feed($facet_id, $value_id, $feed);
386
+ } else {
387
+ $result = $this->query->remove_filter($facet_id, $value_id);
388
+ }
389
  } else {
390
  if ($facet->has_single_mode()) {
391
+ if (! is_null($feed)) {
392
+ $result = $this->query->set_filter_on_feed($facet_id, array($value_id), $feed);
393
+ } else {
394
+ $result = $this->query->set_filter($facet_id, $value_id);
395
+ }
396
  } else {
397
+ if (! is_null($feed)) {
398
+ $result = $this->query->add_filter_on_feed($facet_id, array($value_id), $feed);
399
+ } else {
400
+ $result = $this->query->add_filter($facet_id, $value_id);
401
+ }
402
  }
403
  }
404
  return $result;
405
  }
406
  }
 
 
lib/antidot/AFS/SEARCH/afs_facet_manager.php CHANGED
@@ -99,6 +99,24 @@ class AfsFacetManager
99
  {
100
  $this->facet_values_sort_order = new AfsFacetValuesSortOrder($mode, $order);
101
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
  /** @brief Checks whether specific sort order has been defined on facet values.
103
  * @return @c True when specific sort order has been defined, @c false otherwise.
104
  */
@@ -255,6 +273,19 @@ class AfsFacetManager
255
  }
256
 
257
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
258
  /** @} */
259
 
260
  /** @name Internal helpers
@@ -290,8 +321,8 @@ class AfsFacetManager
290
 
291
  private function is_mode_sticky($mode)
292
  {
293
- if (AfsFacetMode::SINGLE_MODE == $mode
294
- || AfsFacetMode::OR_MODE == $mode) {
295
  return true;
296
  } else {
297
  return false;
99
  {
100
  $this->facet_values_sort_order = new AfsFacetValuesSortOrder($mode, $order);
101
  }
102
+
103
+ /** @brief Defines values sort order for one specific facet id.
104
+ *
105
+ * AFS search default sort for facet values is alphanumeric. This method
106
+ * allows to change this behaviour.
107
+ *
108
+ * @param $facet_id [in] id of facet to configure
109
+ * @param $mode [in] Sort mode (see AfsFacetValuesSortMode).
110
+ * @param $order [in] Sort order (see AfsSortOrder).
111
+ *
112
+ * @exception InvalidArgumentException when $mode or $order is invalid.
113
+ */
114
+ public function set_facet_values_sort_order($facet_id, $mode, $order)
115
+ {
116
+ $facet = $this->get_facet($facet_id);
117
+ $facet->set_values_sort_order($mode, $order);
118
+ }
119
+
120
  /** @brief Checks whether specific sort order has been defined on facet values.
121
  * @return @c True when specific sort order has been defined, @c false otherwise.
122
  */
273
  }
274
 
275
  }
276
+
277
+ public function format() {
278
+ $facets_sorts = array();
279
+ foreach ($this->facets as $facet) {
280
+ if (! is_null($sort_order = $facet->get_values_sort_order()) ) {
281
+ list($sort, $order) = $sort_order->format();
282
+ $facets_sorts[] = $facet->get_id() . ',sort='. $sort;
283
+ $facets_sorts[] = $facet->get_id() . ',order='. $order;
284
+ }
285
+ }
286
+ return array('facet' => $facets_sorts);
287
+ }
288
+
289
  /** @} */
290
 
291
  /** @name Internal helpers
321
 
322
  private function is_mode_sticky($mode)
323
  {
324
+ if (AfsFacetMode::OR_MODE == $mode
325
+ || AfsFacetMode::STICKY_AND_MODE == $mode) {
326
  return true;
327
  } else {
328
  return false;
lib/antidot/AFS/SEARCH/afs_facet_mode.php CHANGED
@@ -8,7 +8,7 @@ require_once 'COMMON/afs_tools.php';
8
  */
9
  class AfsFacetMode extends BasicEnum
10
  {
11
- private static $instance = null;
12
 
13
  static public function check_value($value, $msg=null)
14
  {
@@ -114,6 +114,38 @@ class AfsFacetMode extends BasicEnum
114
  */
115
  const AND_MODE = 'AND_MODE';
116
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
117
  /** @brief Unspecified mode.
118
  *
119
  * When a facet is built with unspecified mode, global mode defined at
8
  */
9
  class AfsFacetMode extends BasicEnum
10
  {
11
+ private static $instance = null;
12
 
13
  static public function check_value($value, $msg=null)
14
  {
114
  */
115
  const AND_MODE = 'AND_MODE';
116
 
117
+ /** @brief Or mode.
118
+ *
119
+ * New value set for the facet is appended to the list of values already
120
+ * set. All the values are and-combined.
121
+ *
122
+ * Example:<br/>
123
+ * Let's suppose your products have colors.
124
+ *
125
+ * - A query without any filter should get a reply with all products and
126
+ * following facet values:
127
+ *
128
+ * - Red (3 products)
129
+ * - Green (7 products)
130
+ * - Blue (4 products)
131
+ *
132
+ * - Then you can filter on Red, reply should only contains Red products
133
+ * whereas facet values are not changed. All the colors
134
+ * are still available so that one can filter on other color.
135
+ *
136
+ * - Red (3 products) X
137
+ * - Green (7 products)
138
+ * - Blue (4 products)
139
+ *
140
+ * - You can add filter on Green so that you get all products that are Red And Green
141
+ * whereas facet values are still unchanged:
142
+ *
143
+ * - Red (3 products) X
144
+ * - Green (7 products) X
145
+ * - Blue (4 products)
146
+ */
147
+ const STICKY_AND_MODE = 'STICKY_AND_MODE';
148
+
149
  /** @brief Unspecified mode.
150
  *
151
  * When a facet is built with unspecified mode, global mode defined at
lib/antidot/AFS/SEARCH/afs_feed_coder.php CHANGED
@@ -73,5 +73,9 @@ class AfsFeedCoder extends AfsCoderBase implements AfsCoderInterface
73
  . preg_quote($this->value_sep) . '|' . preg_quote($this->escape)
74
  . ')', '$1', $value);
75
  }
 
 
 
 
76
  }
77
 
73
  . preg_quote($this->value_sep) . '|' . preg_quote($this->escape)
74
  . ')', '$1', $value);
75
  }
76
+
77
+ public function get_separator() {
78
+ return $this->value_sep;
79
+ }
80
  }
81
 
lib/antidot/AFS/SEARCH/afs_filter_coder.php CHANGED
@@ -89,5 +89,9 @@ class AfsFilterCoder extends AfsCoderBase implements AfsCoderInterface
89
  . preg_quote($this->value_sep) . '|' . preg_quote($this->filter_sep)
90
  . '|' . preg_quote($this->escape) . ')', '$1', $value);
91
  }
 
 
 
 
92
  }
93
 
89
  . preg_quote($this->value_sep) . '|' . preg_quote($this->filter_sep)
90
  . '|' . preg_quote($this->escape) . ')', '$1', $value);
91
  }
92
+
93
+ public function get_separator() {
94
+ return $this->filter_sep;
95
+ }
96
  }
97
 
lib/antidot/AFS/SEARCH/afs_filter_parameter.php ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Created by PhpStorm.
4
+ * User: ct
5
+ * Date: 2/6/15
6
+ * Time: 3:49 PM
7
+ */
8
+
9
+ class AfsFilterParameter extends AfsMultipleValuesParameter {
10
+ protected $facet_id;
11
+
12
+ public function __construct($facetId, $values, $feed=null) {
13
+ parent::__construct('filter', $values, $feed);
14
+ $this->facet_id = $facetId;
15
+ }
16
+
17
+ public function get_facet_id() {
18
+ return $this->facet_id;
19
+ }
20
+
21
+ public function format () {
22
+ return array($this->facet_id => $this->values);
23
+ }
24
+ }
lib/antidot/AFS/SEARCH/afs_fts_mode.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once 'COMMON/afs_tools.php';
4
+
5
+ class AfsFtsMode extends BasicEnum {
6
+
7
+ private static $instance = null;
8
+
9
+ static public function check_value($value, $msg=null)
10
+ {
11
+ if (is_null(self::$instance))
12
+ self::$instance = new self();
13
+ BasicEnum::check_val(self::$instance, $value, $msg);
14
+ }
15
+
16
+ const MANDATORY = 'mandatory';
17
+ const OPTIONAL = 'optional';
18
+ }
lib/antidot/AFS/SEARCH/afs_pager_helper.php CHANGED
@@ -15,6 +15,7 @@ class AfsPagerHelper extends AfsHelperBase
15
  private $last_page = null;
16
  private $query = null;
17
  private $config = null;
 
18
  const PREVIOUS_NAME = 'previousPage';
19
  const NEXT_NAME = 'nextPage';
20
  const CURRENT_NAME = 'currentPage';
@@ -40,6 +41,7 @@ class AfsPagerHelper extends AfsHelperBase
40
  $this->pager = $pager;
41
  $this->query = $query;
42
  $this->config = $config;
 
43
  $this->initialize_last_page($meta);
44
  }
45
 
@@ -54,7 +56,7 @@ class AfsPagerHelper extends AfsHelperBase
54
  {
55
  $result = array();
56
  foreach ($this->pager->page as $page) {
57
- $query = $this->query->set_page($page);
58
  $result[$page] = $this->config->has_query_coder()
59
  ? $this->config->get_query_coder()->generate_link($query)
60
  : $query;
@@ -113,7 +115,7 @@ class AfsPagerHelper extends AfsHelperBase
113
  private function initialize_last_page($meta)
114
  {
115
  $page_no = ceil($meta->get_total_replies() / $meta->get_replies_per_page());
116
- $query = $this->query->set_page($page_no);
117
  if ($this->config->has_query_coder())
118
  $second = $this->config->get_query_coder()->generate_link($query);
119
  else
@@ -189,7 +191,7 @@ class AfsPagerHelper extends AfsHelperBase
189
  private function get_typed($type)
190
  {
191
  if (property_exists($this->pager, $type)) {
192
- $query = $this->query->set_page($this->pager->$type);
193
  return $this->config->has_query_coder()
194
  ? $this->config->get_query_coder()->generate_link($query) : $query;
195
  } else {
15
  private $last_page = null;
16
  private $query = null;
17
  private $config = null;
18
+ private $feed_name = null;
19
  const PREVIOUS_NAME = 'previousPage';
20
  const NEXT_NAME = 'nextPage';
21
  const CURRENT_NAME = 'currentPage';
41
  $this->pager = $pager;
42
  $this->query = $query;
43
  $this->config = $config;
44
+ $this->feed_name = $meta->get_feed();
45
  $this->initialize_last_page($meta);
46
  }
47
 
56
  {
57
  $result = array();
58
  foreach ($this->pager->page as $page) {
59
+ $query = $this->query->set_page($page, $this->feed_name);
60
  $result[$page] = $this->config->has_query_coder()
61
  ? $this->config->get_query_coder()->generate_link($query)
62
  : $query;
115
  private function initialize_last_page($meta)
116
  {
117
  $page_no = ceil($meta->get_total_replies() / $meta->get_replies_per_page());
118
+ $query = $this->query->set_page($page_no, $this->feed_name);
119
  if ($this->config->has_query_coder())
120
  $second = $this->config->get_query_coder()->generate_link($query);
121
  else
191
  private function get_typed($type)
192
  {
193
  if (property_exists($this->pager, $type)) {
194
+ $query = $this->query->set_page($this->pager->$type, $this->feed_name);
195
  return $this->config->has_query_coder()
196
  ? $this->config->get_query_coder()->generate_link($query) : $query;
197
  } else {
lib/antidot/AFS/SEARCH/afs_promote_banner_reply_helper.php ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Created by PhpStorm.
4
+ * User: ct
5
+ * Date: 2/13/15
6
+ * Time: 11:04 AM
7
+ */
8
+ require_once "AFS/SEARCH/afs_promote_reply_helper.php";
9
+
10
+
11
+ class AfsPromoteBannerReplyHelper extends AfsPromoteReplyHelper {
12
+ protected $url;
13
+ protected $image_url;
14
+
15
+ public function __construct($reply)
16
+ {
17
+ parent::__construct($reply);
18
+ $this->image_url = $this->clientdata->get_value('/promote/afs:images/afs:image/afs:imageUrl', array('afs' => 'http://ref.antidot.net/7.3/bo.xsd'));
19
+ $this->url = $this->clientdata->get_value('/promote/afs:images/afs:image/afs:url', array('afs' => 'http://ref.antidot.net/7.3/bo.xsd'));
20
+ }
21
+
22
+ /**
23
+ * @return string, the url used for redirection
24
+ */
25
+ public function get_url() {
26
+ return $this->url;
27
+ }
28
+
29
+ /**
30
+ * @return string, the url of banner image
31
+ */
32
+ public function get_image_url() {
33
+ return $this->image_url;
34
+ }
35
+
36
+ /**
37
+ * @brief get the current promote instance type, types are default, banner or redirect
38
+ * @return string 'default', 'banner' or 'redirect'
39
+ */
40
+ public function get_type() {
41
+ return "banner";
42
+ }
43
+ }
lib/antidot/AFS/SEARCH/afs_promote_redirect_reply_helper.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Created by PhpStorm.
4
+ * User: ct
5
+ * Date: 2/13/15
6
+ * Time: 11:05 AM
7
+ */
8
+
9
+ require_once "AFS/SEARCH/afs_promote_reply_helper.php";
10
+
11
+
12
+ class AfsPromoteRedirectReplyHelper extends AfsBaseReplyHelper {
13
+ protected $url;
14
+
15
+ public function __construct($reply)
16
+ {
17
+ $this->url = $reply->uri;
18
+ }
19
+
20
+ /**
21
+ * @return string, the url used for redirection
22
+ */
23
+ public function get_url() {
24
+ return $this->url;
25
+ }
26
+
27
+ /**
28
+ * @brief get the current promote instance type, types are default, banner or redirect
29
+ * @return string 'default', 'banner' or 'redirect'
30
+ */
31
+ public function get_type() {
32
+ return "redirect";
33
+ }
34
+ }
lib/antidot/AFS/SEARCH/afs_promote_reply_helper.php CHANGED
@@ -16,7 +16,7 @@ require_once "AFS/SEARCH/afs_client_data_helper.php";
16
  */
17
  class AfsPromoteReplyHelper extends AfsBaseReplyHelper
18
  {
19
- private $clientdata_mgr = null;
20
 
21
  /** @brief Constructs new instance.
22
  * @param $reply [in] one reply used to initialize the instance.
@@ -24,12 +24,26 @@ class AfsPromoteReplyHelper extends AfsBaseReplyHelper
24
  public function __construct($reply)
25
  {
26
  parent::__construct($reply, new AfsRawTextVisitor());
27
- if (property_exists($this->reply, 'clientData')) {
28
- $this->clientdata_mgr = new AfsClientDataManager($this->reply->clientData);
29
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  }
31
 
32
  /** @brief Retrieves custom data from promote reply.
 
33
  * @param $key [in] Identifier of the custom resource. When not specified
34
  * custom data are returned as key/value pairs.
35
  * @return value(s) associated to specified key or all key/value pairs.
@@ -37,41 +51,29 @@ class AfsPromoteReplyHelper extends AfsBaseReplyHelper
37
  */
38
  public function get_custom_data($key=null)
39
  {
40
- if (is_null($this->clientdata_mgr)) {
41
  throw new Exception('No custom data available for this promote ('
42
  . $this->get_title() . ')');
43
  }
44
 
45
- $clientdata = null;
46
- try {
47
- $clientdata = $this->clientdata_mgr->get_clientdata();
48
- } catch (OutOfBoundsException $e) {
49
- throw new Exception('Custom data with default identifier is not available!');
50
- }
51
-
52
- if ('application/xml' != $clientdata->get_mime_type()) {
53
- throw new Exception('Custom data is not store in XML format, update'
54
- . ' your PHP connector or contact Antidot support team.');
55
- }
56
-
57
  if (is_null($key)) {
58
- return $this->extract_key_value_pairs($clientdata);
59
  } else {
60
- return $clientdata->get_value("/afs:customData/afs:$key",
61
  array('afs' => 'http://ref.antidot.net/7.3/bo.xsd'));
62
  }
63
  }
64
 
65
- private function extract_key_value_pairs($clientData)
66
  {
67
  $result = array();
68
- $doc = new DOMDocument();
69
- $doc->loadXML($clientData->get_value());
70
- if ($doc->hasChildNodes() && $doc->childNodes->item(0)->hasChildNodes()) {
71
- foreach ($doc->childNodes->item(0)->childNodes as $node) {
72
- $result[$node->localName] = $node->nodeValue;
73
- }
74
  }
 
 
75
  return $result;
76
  }
77
  }
16
  */
17
  class AfsPromoteReplyHelper extends AfsBaseReplyHelper
18
  {
19
+ protected $clientdata = null;
20
 
21
  /** @brief Constructs new instance.
22
  * @param $reply [in] one reply used to initialize the instance.
24
  public function __construct($reply)
25
  {
26
  parent::__construct($reply, new AfsRawTextVisitor());
27
+ $xmlstring = $reply->clientData[0]->contents;
28
+ $xmlstring = '<promote>' . $xmlstring . '</promote>';
29
+ $clientdata = clone $reply->clientData[0];
30
+ $clientdata->contents = $xmlstring;
31
+
32
+ $clientdata = new AfsXmlClientDataHelper($clientdata);
33
+
34
+ $this->clientdata = $clientdata;
35
+ }
36
+
37
+ /**
38
+ * @brief get the current promote instance type, types are default, banner or redirect
39
+ * @return string 'default', 'banner' or 'redirect'
40
+ */
41
+ public function get_type() {
42
+ return 'default';
43
  }
44
 
45
  /** @brief Retrieves custom data from promote reply.
46
+ * To call this method, get_type should return 'default'
47
  * @param $key [in] Identifier of the custom resource. When not specified
48
  * custom data are returned as key/value pairs.
49
  * @return value(s) associated to specified key or all key/value pairs.
51
  */
52
  public function get_custom_data($key=null)
53
  {
54
+ if (is_null($this->clientdata)) {
55
  throw new Exception('No custom data available for this promote ('
56
  . $this->get_title() . ')');
57
  }
58
 
 
 
 
 
 
 
 
 
 
 
 
 
59
  if (is_null($key)) {
60
+ return $this->extract_key_value_pairs();
61
  } else {
62
+ return $this->clientdata->get_value("/promote/afs:customData/afs:$key",
63
  array('afs' => 'http://ref.antidot.net/7.3/bo.xsd'));
64
  }
65
  }
66
 
67
+ private function extract_key_value_pairs()
68
  {
69
  $result = array();
70
+ $customdata = $this->clientdata->get_node('/promote/afs:customData', array("afs" => "http://ref.antidot.net/7.3/bo.xsd"));
71
+
72
+ foreach (array_shift($customdata) as $key => $value) {
73
+ $result[$key] = $value;
 
 
74
  }
75
+
76
+
77
  return $result;
78
  }
79
  }
lib/antidot/AFS/SEARCH/afs_query.php CHANGED
@@ -4,9 +4,14 @@ require_once 'AFS/afs_query_base.php';
4
  require_once 'AFS/SEARCH/afs_sort_order.php';
5
  require_once 'AFS/SEARCH/afs_sort_builtins.php';
6
  require_once 'AFS/SEARCH/afs_cluster_exception.php';
 
7
  require_once 'AFS/SEARCH/afs_count.php';
8
  require_once 'AFS/SEARCH/afs_facet_manager.php';
9
  require_once 'AFS/SEARCH/afs_facet_default.php';
 
 
 
 
10
 
11
  /** @brief Represent an AFS query.
12
  *
@@ -31,16 +36,20 @@ class AfsQuery extends AfsQueryBase
31
  {
32
  protected $facet_mgr = null;
33
 
34
- protected $filter = array(); // afs:filter
35
- protected $page = 1; // afs:page
 
36
  protected $lang = null; // afs:lang
37
  protected $sort = array(); // afs:sort
 
38
  protected $facetDefault = null; // afs:facetDefault
39
  protected $cluster = null;
40
  protected $maxClusters = null;
41
  protected $overspill = null;
42
  protected $count = null; // afs:count for cluster mode
43
  protected $advancedFilter = array(); // exposed only to AFS search engine
 
 
44
 
45
  /**
46
  * @brief Construct new AFS query object.
@@ -52,21 +61,33 @@ class AfsQuery extends AfsQueryBase
52
  parent::__construct($afs_query);
53
  if ($afs_query != null) {
54
  $this->facet_mgr = $afs_query->facet_mgr->copy();
55
- $this->filter = $afs_query->filter;
56
- $this->page = $afs_query->page;
57
- $this->lang = $afs_query->lang;
58
- $this->sort = $afs_query->sort;
 
 
 
 
 
 
 
 
59
  $this->facetDefault = $afs_query->facetDefault->copy();
60
- $this->cluster = $afs_query->cluster;
61
  $this->maxClusters = $afs_query->maxClusters;
62
  $this->overspill = $afs_query->overspill;
63
- $this->count = $afs_query->count;
64
  $this->advancedFilter = $afs_query->advancedFilter;
 
 
 
65
  } else {
66
  $this->facet_mgr = new AfsFacetManager();
67
  $this->lang = new AfsLanguage(null);
68
  $this->facetDefault = new AfsFacetDefault();
69
  $this->auto_set_from = false;
 
70
  }
71
  }
72
 
@@ -84,7 +105,55 @@ class AfsQuery extends AfsQueryBase
84
  * Page number is reset. */
85
  protected function on_assignment()
86
  {
87
- $this->reset_page();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
  }
89
 
90
 
@@ -99,12 +168,53 @@ class AfsQuery extends AfsQueryBase
99
  public function set_filter($facet_id, $values)
100
  {
101
  $copy = $this->copy();
102
- $copy->on_assignment();
103
- if (! is_array($values))
104
  $values = array($values);
105
- $copy->filter[$facet_id] = $values;
106
- return $this->auto_set_from ? $copy->set_from(AfsOrigin::FACET) : $copy;
 
 
 
 
 
 
 
 
 
 
 
 
107
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108
  /** @brief Assign new value(s) to specific facet.
109
  * @param $facet_id [in] id of the facet for which new @a value should be
110
  * added.
@@ -114,14 +224,55 @@ class AfsQuery extends AfsQueryBase
114
  public function add_filter($facet_id, $values)
115
  {
116
  $copy = $this->copy();
117
- $copy->on_assignment();
118
- if (empty($copy->filter[$facet_id]))
119
- $copy->filter[$facet_id] = array();
120
  if (! is_array($values))
121
  $values = array($values);
122
- $copy->filter[$facet_id] = array_merge($copy->filter[$facet_id], $values);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
123
  return $this->auto_set_from ? $copy->set_from(AfsOrigin::FACET) : $copy;
124
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125
  /** @brief Remove existing value from specific facet.
126
  * @remark No error is reported when the removed @a value is not already set.
127
  * @param $facet_id [in] id of the facet to update.
@@ -132,56 +283,182 @@ class AfsQuery extends AfsQueryBase
132
  public function remove_filter($facet_id, $value)
133
  {
134
  $copy = $this->copy();
135
- $copy->on_assignment();
136
- if (! empty($copy->filter[$facet_id])) {
137
- $pos = array_search($value, $copy->filter[$facet_id]);
138
- unset($copy->filter[$facet_id][$pos]);
139
- if (empty($copy->filter[$facet_id]))
140
- unset($copy->filter[$facet_id]);
 
 
 
 
 
 
 
 
 
 
 
 
141
  }
 
142
  return $this->auto_set_from ? $copy->set_from(AfsOrigin::FACET) : $copy;
143
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
144
  /** @brief Check whether instance has a @a value associated with specified
145
  * facet id.
146
  * @param $facet_id [in] id of the facet to check.
147
  * @param $value [in] value to check in the list of values for the given
148
  * @a facet_id.
 
149
  * @return true when the @a value is present in the list of values
150
  * associated with @a facet_id, false otherwise. Always false when provided
151
  * @a facet_id is unknown.
152
  */
153
- public function has_filter($facet_id, $value)
154
  {
155
- if (empty($this->filter[$facet_id])) {
 
 
 
 
 
 
 
156
  return false;
157
  } else {
158
- if (! isset($value))
159
- return true;
160
- else
161
- return in_array($value, $this->filter[$facet_id]);
 
 
162
  }
163
  }
164
  /** @brief Retrieve the list of values for specific facet id.
165
  * @remark You should ensure that the required @a facet_id is valid.
166
  * @param $facet_id [in] facet id to consider.
 
167
  * @return list of values associated to the given @a facet_id.
168
  */
169
- public function get_filter_values($facet_id)
170
  {
171
- if (array_key_exists($facet_id, $this->filter)) {
172
- return $this->filter[$facet_id];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
173
  }
174
- throw new AfsFilterException("$facet_id doesn't exist");
175
  }
176
  /** @brief Retrieve the list of all managed facet ids.
177
  *
178
  * Only elements from this list should be used to query @a get_filter_values
179
  * method.
 
180
  * @return list of facet ids.
181
  */
182
- public function get_filters()
183
  {
184
- return array_keys($this->filter);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
185
  }
186
  /** @} */
187
 
@@ -240,35 +517,42 @@ class AfsQuery extends AfsQueryBase
240
  * @{ */
241
 
242
  /** @brief Check whether reply page is set.
 
243
  * @return always true.
244
  */
245
- public function has_page()
246
  {
247
- return $this->page != null;
248
  }
249
  /** @brief Define new result page.
250
  * @param $page [in] result page to output. It should be greater than or
251
  * equal to 1.
 
252
  * @return new up to date instance.
253
- * @exception Exception on invalid page number.
254
  */
255
- public function set_page($page)
256
  {
257
  if ($page <= 0)
258
  {
259
  throw new Exception('Invalid page number: ' . $page);
260
  }
 
261
  $copy = $this->copy();
262
- $copy->page = $page;
 
 
 
263
  return $this->auto_set_from ? $copy->set_from(AfsOrigin::PAGER) : $copy;
264
  }
265
  /** @brief Retrieve current reply page.
266
- * @remark For a new query, this vaue is reset to 1.
 
267
  * @return reply page number.
268
  */
269
- public function get_page()
270
  {
271
- return $this->page;
272
  }
273
  /** @brief Shortcut for @a set_page(1).
274
  *
@@ -276,7 +560,8 @@ class AfsQuery extends AfsQueryBase
276
  */
277
  protected function reset_page()
278
  {
279
- return $this->page = 1;
 
280
  }
281
  /** @} */
282
 
@@ -327,16 +612,33 @@ class AfsQuery extends AfsQueryBase
327
  /** @brief Checks whether sort parameter is set.
328
  * @param $name [in] check this specific parameter name (default=null:
329
  * checks whether at least one sort parameter is set).
 
330
  * @return true when sort parameter is set, false otherwise.
331
  */
332
- public function has_sort($name=null)
333
  {
 
 
 
 
 
 
 
 
 
 
 
334
  if (is_null($name)) {
335
- return ! empty($this->sort);
336
  } else {
337
- return array_key_exists($name, $this->sort);
 
 
 
 
338
  }
339
  }
 
340
  /** @brief Resets sort order to AFS default sort order.
341
  */
342
  public function reset_sort()
@@ -353,13 +655,26 @@ class AfsQuery extends AfsQueryBase
353
  * @a reset_sort.
354
  * @param $order [in] order applied to the given parameter. Allowed values
355
  * are AfsSortOrder::DESC (default) or AfsSortOrder:ASC.
356
- *
357
  * @exception Exception when provided sort parameter does not conform to
358
  * required syntax.
359
  */
360
- public function set_sort($sort_param, $order=AfsSortOrder::DESC)
361
  {
362
- return $this->internal_add_sort(null, $sort_param, $order);
 
 
 
 
 
 
 
 
 
 
 
 
 
363
  }
364
  /** @brief Defines additional sort order.
365
  *
@@ -372,44 +687,73 @@ class AfsQuery extends AfsQueryBase
372
  * @a reset_sort.
373
  * @param $order [in] order applied to the given parameter. Allowed values
374
  * are AfsSortOrder::DESC (default) or AfsSortOrder:ASC.
375
- *
376
  * @exception Exception when provided sort parameter does not conform to
377
  * required syntax.
378
  */
379
- public function add_sort($sort_param, $order=AfsSortOrder::DESC)
380
  {
381
- return $this->internal_add_sort($this->sort, $sort_param, $order);
 
 
 
 
 
 
 
 
 
 
 
 
382
  }
383
  /** @brief Retrieves sort order.
384
  * @deprecated This method will be removed soon!
 
385
  * @return sort order as string.
386
  */
387
- public function get_sort()
388
  {
389
  $result = '';
390
  $sorts = array();
391
- foreach ($this->sort as $k => $v) {
392
- $sorts[] = $k . ',' . $v;
393
- }
394
- if (! empty($sorts)) {
395
- $result = implode(';', $sorts);
 
 
 
 
 
396
  }
397
  return $result;
398
  }
399
  /** @brief Retrieves sort order of the specified parameter.
400
  * @param $name [in] parameter name to check.
 
401
  * @return AfsSortOrder::ASC or AfsSortOrder::DESC.
402
  * @exception OutOfBoundsException when required sort parameter is not
403
  * defined.
404
  */
405
- public function get_sort_order($name)
406
  {
407
- if (array_key_exists($name, $this->sort)) {
408
- return $this->sort[$name];
 
 
409
  } else {
410
- throw new OutOfBoundsException('Unknown sort parameter: ' . $name);
411
  }
 
 
 
 
 
 
 
412
  }
 
413
  /** @brief Adds new sort parameter or substitutes existing one.
414
  *
415
  * @param $current_value [in] current sort order value.
@@ -418,7 +762,7 @@ class AfsQuery extends AfsQueryBase
418
  *
419
  * @return copy of current query.
420
  */
421
- private function internal_add_sort($current_value, $sort_param, $order)
422
  {
423
  if ($sort_param == '') {
424
  $sort_param = null;
@@ -432,15 +776,16 @@ class AfsQuery extends AfsQueryBase
432
  AfsSortOrder::check_value($order, 'Invalid sort order provided: ');
433
 
434
  $new_value = $current_value;
435
- $new_value[$sort_param] = $order;
 
 
 
 
436
  } else {
437
  $new_value = array();
438
  }
439
 
440
- $copy = $this->copy();
441
- $copy->on_assignment();
442
- $copy->sort = $new_value;
443
- return $copy;
444
  }
445
  /** @} */
446
 
@@ -464,8 +809,8 @@ class AfsQuery extends AfsQueryBase
464
  public function set_cluster($facet_id, $replies_per_cluster)
465
  {
466
  $copy = $this->copy();
467
- $copy->on_assignment();
468
- $copy->cluster = $facet_id . ',' . $replies_per_cluster;
469
  return $copy;
470
  }
471
  /** @brief Unsets cluster definition.
@@ -486,8 +831,8 @@ class AfsQuery extends AfsQueryBase
486
  */
487
  public function get_cluster_id()
488
  {
489
- $tmp = $this->get_splitted_cluster_definition();
490
- return $tmp[0];
491
  }
492
  /** @brief Retrieves maximum number of replies per cluster.
493
  * @return Number of replies per cluster reply.
@@ -495,8 +840,8 @@ class AfsQuery extends AfsQueryBase
495
  */
496
  public function get_nb_replies_per_cluster()
497
  {
498
- $tmp = $this->get_splitted_cluster_definition();
499
- return $tmp[1];
500
  }
501
  /** @internal
502
  * @brief Split cluster property to retrieve facet id and nb replies per cluster.
@@ -504,7 +849,7 @@ class AfsQuery extends AfsQueryBase
504
  private function get_splitted_cluster_definition()
505
  {
506
  $this->check_cluster_initialization();
507
- return explode(',', $this->cluster);
508
  }
509
  /** @brief Checks whether number of cluster is limited.
510
  *
@@ -523,7 +868,7 @@ class AfsQuery extends AfsQueryBase
523
  {
524
  $this->check_cluster_initialization();
525
  $copy = $this->copy();
526
- $copy->on_assignment();
527
  $copy->maxClusters = $max_nb_of_clusters;
528
  return $copy;
529
  }
@@ -575,9 +920,9 @@ class AfsQuery extends AfsQueryBase
575
  * @return Current count mode. AfsCount::DOCUMENTS, AfsCount::CLUSTERS or
576
  * @c null when no specific count mode has been set.
577
  */
578
- public function get_count_mode()
579
  {
580
- return $this->count;
581
  }
582
  /** @brief Defines new count mode.
583
  *
@@ -587,14 +932,16 @@ class AfsQuery extends AfsQueryBase
587
  *
588
  * @return new up to date instance.
589
  */
590
- public function set_count($count_mode)
591
  {
592
  $this->check_cluster_initialization();
593
  if (!is_null($count_mode))
594
  AfsCount::check_value($count_mode, 'Invalid count mode: ');
595
  $copy = $this->copy();
596
- $copy->on_assignment();
597
- $copy->count = $count_mode;
 
 
598
  return $copy;
599
  }
600
  /** @internal
@@ -625,10 +972,18 @@ class AfsQuery extends AfsQueryBase
625
  foreach ($params as $param => $values) {
626
  $adder = 'add_' . $param;
627
  $setter = 'set_' . $param;
628
- if ($param == 'filter') {
 
 
 
 
 
629
  foreach ($values as $filter => $filter_values) {
630
  foreach ($filter_values as $value) {
631
- $result = $result->add_filter($filter, $value);
 
 
 
632
  }
633
  }
634
  } elseif ($param == 'sort') {
@@ -646,7 +1001,7 @@ class AfsQuery extends AfsQueryBase
646
  $result->set_custom_parameter($param, $values);
647
  }
648
  }
649
- $result->page = $page;
650
  return $result;
651
  }
652
 
@@ -654,11 +1009,14 @@ class AfsQuery extends AfsQueryBase
654
  {
655
  $result = new AfsQuery();
656
  if (array_key_exists('cluster', $params)) {
657
- $result->cluster = $params['cluster'];
 
 
658
  unset($params['cluster']);
659
  }
660
  if (array_key_exists('page', $params)) {
661
- $result->page = $params['page'];
 
662
  unset($params['page']);
663
  }
664
  return $result;
@@ -667,9 +1025,11 @@ class AfsQuery extends AfsQueryBase
667
 
668
  protected function get_relevant_parameters()
669
  {
670
- $params = array('filter', 'sort', 'cluster', 'maxClusters', 'overspill', 'count');
671
- if ($this->page != 1)
 
672
  $params[] = 'page';
 
673
  if (! is_null($this->lang->lang))
674
  $params[] = 'lang';
675
  return $params;
@@ -677,7 +1037,7 @@ class AfsQuery extends AfsQueryBase
677
 
678
  protected function get_additional_parameters()
679
  {
680
- return array('facetDefault', 'advancedFilter');
681
  }
682
  /** @} */
683
 
@@ -767,6 +1127,24 @@ class AfsQuery extends AfsQueryBase
767
  return $copy;
768
  }
769
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
770
  /** @brief Defines maximum number of facet values replied per facet.
771
  *
772
  * Default maximum value is 1000.
@@ -796,19 +1174,31 @@ class AfsQuery extends AfsQueryBase
796
  }
797
  /** @brief Defines multi-selection mode for one or more facets.
798
  *
799
- * See AfsSearch::set_default_multi_selection_facets or
800
- * AfsFacetMode::OR_MODE for more details.
801
  *
802
  * @remark Parameters: one (string) or more facet identifiers (individual
803
  * strings or array of strings).
804
  */
805
- public function set_multi_selection_facets($ids)
806
  {
807
  $args = get_function_args_as_array(func_get_args());
 
 
 
 
 
 
 
 
 
 
 
808
  $copy = $this->copy();
809
- $copy->facet_mgr->set_facets_mode(AfsFacetMode::OR_MODE, $args);
810
  return $copy;
811
  }
 
812
  /** @brief Defines mono-selection mode for one or more facets.
813
  *
814
  * See AfsSearch::set_default_mono_selection_facets or
@@ -824,6 +1214,40 @@ class AfsQuery extends AfsQueryBase
824
  $copy->facet_mgr->set_facets_mode(AfsFacetMode::SINGLE_MODE, $args);
825
  return $copy;
826
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
827
  /** @} */
828
  }
829
 
4
  require_once 'AFS/SEARCH/afs_sort_order.php';
5
  require_once 'AFS/SEARCH/afs_sort_builtins.php';
6
  require_once 'AFS/SEARCH/afs_cluster_exception.php';
7
+ require_once 'AFS/SEARCH/afs_cluster_exception.php';
8
  require_once 'AFS/SEARCH/afs_count.php';
9
  require_once 'AFS/SEARCH/afs_facet_manager.php';
10
  require_once 'AFS/SEARCH/afs_facet_default.php';
11
+ require_once 'AFS/SEARCH/afs_fts_mode.php';
12
+ require_once 'AFS/SEARCH/afs_filter_parameter.php';
13
+ require_once 'AFS/SEARCH/afs_sort_parameter.php';
14
+ require_once 'AFS/SEARCH/afs_cluster_parameter.php';
15
 
16
  /** @brief Represent an AFS query.
17
  *
36
  {
37
  protected $facet_mgr = null;
38
 
39
+ protected $filter = array(); // afs:filter, filter on facets ids
40
+ protected $nativeFunctionFilter = array(); // use native search engine function such as geo:dist, vfst ...
41
+ protected $page; // afs:page
42
  protected $lang = null; // afs:lang
43
  protected $sort = array(); // afs:sort
44
+ protected $nativeFunctionSort = array();
45
  protected $facetDefault = null; // afs:facetDefault
46
  protected $cluster = null;
47
  protected $maxClusters = null;
48
  protected $overspill = null;
49
  protected $count = null; // afs:count for cluster mode
50
  protected $advancedFilter = array(); // exposed only to AFS search engine
51
+ protected $ftsDefault = null; // afs:ftsDefault
52
+ protected $clientData = array(); // afs:clientData
53
 
54
  /**
55
  * @brief Construct new AFS query object.
61
  parent::__construct($afs_query);
62
  if ($afs_query != null) {
63
  $this->facet_mgr = $afs_query->facet_mgr->copy();
64
+
65
+ foreach ($afs_query->filter as $filter) {
66
+ $this->filter[] = clone $filter;
67
+ }
68
+
69
+ if (! is_null($afs_query->page)) $this->page = clone $afs_query->page;
70
+ if (! is_null($afs_query->lang)) $this->lang = clone $afs_query->lang;
71
+
72
+ foreach ($afs_query->sort as $sort) {
73
+ $this->sort[] = clone $sort;
74
+ }
75
+
76
  $this->facetDefault = $afs_query->facetDefault->copy();
77
+ if (!is_null($afs_query->cluster)) $this->cluster = clone $afs_query->cluster;
78
  $this->maxClusters = $afs_query->maxClusters;
79
  $this->overspill = $afs_query->overspill;
80
+ if (! is_null($afs_query->count)) $this->count = clone $afs_query->count;
81
  $this->advancedFilter = $afs_query->advancedFilter;
82
+ $this->ftsDefault = $afs_query->ftsDefault;
83
+ $this->clientData = $afs_query->clientData;
84
+ $this->nativeFunctionFilter = $afs_query->nativeFunctionFilter;
85
  } else {
86
  $this->facet_mgr = new AfsFacetManager();
87
  $this->lang = new AfsLanguage(null);
88
  $this->facetDefault = new AfsFacetDefault();
89
  $this->auto_set_from = false;
90
+ $this->page = new AfsSingleValueParameter('page', 1);
91
  }
92
  }
93
 
105
  * Page number is reset. */
106
  protected function on_assignment()
107
  {
108
+ return $this->reset_page();
109
+ }
110
+
111
+ /**
112
+ * @brief set a new filter on native function
113
+ * @param AfsFilterWrapper $filter
114
+ */
115
+ private function set_native_function_filter(AfsFilterWrapper $filter) {
116
+ array_push($this->nativeFunctionFilter, $filter->to_string());
117
+ }
118
+
119
+ /**
120
+ * @brief remove a filter on native function if exists
121
+ * @param $native_function
122
+ */
123
+ private function remove_native_function_filter($native_function) {
124
+ // removed existing function filter
125
+ foreach ($this->nativeFunctionFilter as $key => $value) {
126
+ if (substr($value, 0, count($native_function))) {
127
+ unset($this->nativeFunctionFilter[$key]);
128
+ break;
129
+ }
130
+ }
131
+ }
132
+
133
+ /**
134
+ * @param $sort
135
+ */
136
+ private function set_native_function_sort($sort) {
137
+ $this->nativeFunctionSort = array($sort);
138
+ }
139
+
140
+ /**
141
+ * @param $native_function
142
+ * @return New
143
+ */
144
+ private function remove_native_function_sort($native_function) {
145
+
146
+ // removed existing geo:dist filter
147
+ $removed = false;
148
+ $cpt = 0;
149
+ while (! $removed && $cpt < count($copy->nativeFunctionSort)) {
150
+ if (substr($copy->nativeFunctionSort[$cpt], 0, count($native_function)) == $native_function) {
151
+ unset($copy->nativeFunctionSort[$cpt]);
152
+ $removed = true;
153
+ } else {
154
+ $cpt++;
155
+ }
156
+ }
157
  }
158
 
159
 
168
  public function set_filter($facet_id, $values)
169
  {
170
  $copy = $this->copy();
171
+ $copy = $copy->on_assignment();
172
+ if (!is_array($values))
173
  $values = array($values);
174
+
175
+ $facet_id_found = false;
176
+ foreach ($copy->filter as $filter) {
177
+ if ($filter->get_facet_id() === $facet_id) {
178
+ $filter->set_values($values);
179
+ $facet_id_found = true;
180
+ }
181
+ }
182
+
183
+ if (! $facet_id_found) {
184
+ $copy->filter[] = new AfsFilterParameter($facet_id, $values);
185
+ }
186
+
187
+ return $this->auto_set_from ? $copy->set_from ( AfsOrigin::FACET ) : $copy;
188
  }
189
+
190
+ /**
191
+ * @brief Assign new value(s) to specific facet on feed replacing any existing one.
192
+ *
193
+ * @param $facet_id [in]
194
+ * id of the facet to update.
195
+ * @param $values [in]
196
+ * new value(s) to filter on.
197
+ * @param $feed [in]
198
+ * feed to filter on
199
+ * @return new up to date instance.
200
+ */
201
+ public function set_filter_on_feed($facet_id, array $values, $feed) {
202
+ $copy = $this->copy ();
203
+ $copy = $copy->on_assignment ();
204
+ if (! is_array ( $values ))
205
+ $values = array ($values);
206
+
207
+ if (($f = $copy->get_feed ( $feed )) != null) {
208
+ $f->set_filter ( $facet_id, $values );
209
+ } else {
210
+ $new_feed = new AfsFeed ( $feed, false );
211
+ $new_feed->set_filter ( $facet_id, $values );
212
+ $copy->feed [] = $new_feed;
213
+ }
214
+
215
+ return $this->auto_set_from ? $copy->set_from ( AfsOrigin::FACET ) : $copy;
216
+ }
217
+
218
  /** @brief Assign new value(s) to specific facet.
219
  * @param $facet_id [in] id of the facet for which new @a value should be
220
  * added.
224
  public function add_filter($facet_id, $values)
225
  {
226
  $copy = $this->copy();
227
+ $copy = $copy->on_assignment();
228
+
 
229
  if (! is_array($values))
230
  $values = array($values);
231
+
232
+ $filters = $copy->filter;
233
+ $filter_exists = false;
234
+ foreach ( $filters as $filter ) {
235
+ if ($filter->get_facet_id () === $facet_id) {
236
+ $filter->add_values ( $values );
237
+ $filter_exists = true;
238
+ break;
239
+ }
240
+ }
241
+ if (! $filter_exists) {
242
+ $filters [] = new AfsFilterParameter ( $facet_id, $values );
243
+ }
244
+
245
+ $copy->filter = $filters;
246
+
247
  return $this->auto_set_from ? $copy->set_from(AfsOrigin::FACET) : $copy;
248
  }
249
+
250
+ /** @brief Assign new value(s) to specific facet.
251
+ * @param $facet_id [in] id of the facet for which new @a value should be
252
+ * added.
253
+ * @param $values [in] value(s) to add to the facet.
254
+ * @param $feed [in] feed to filter on
255
+ * @return new up to date instance.
256
+ */
257
+ public function add_filter_on_feed($facet_id, $values, $feed)
258
+ {
259
+ $copy = $this->copy();
260
+ $copy = $copy->on_assignment();
261
+
262
+ if (! is_array($values))
263
+ $values = array($values);
264
+
265
+ if (($f = $copy->get_feed ( $feed )) != null) {
266
+ $f->add_filter ( $facet_id, $values );
267
+ } else {
268
+ $new_feed = new AfsFeed ( $feed, false );
269
+ $new_feed->set_filter ( $facet_id, $values );
270
+ $copy->feed [] = $new_feed;
271
+ }
272
+
273
+ return $this->auto_set_from ? $copy->set_from(AfsOrigin::FACET) : $copy;
274
+ }
275
+
276
  /** @brief Remove existing value from specific facet.
277
  * @remark No error is reported when the removed @a value is not already set.
278
  * @param $facet_id [in] id of the facet to update.
283
  public function remove_filter($facet_id, $value)
284
  {
285
  $copy = $this->copy();
286
+ $copy = $copy->on_assignment();
287
+
288
+ $filters = $copy->filter;
289
+ foreach ( $filters as $filter ) {
290
+ if ($filter->get_facet_id () === $facet_id) {
291
+ $current_values = $filter->get_values ();
292
+ $pos = array_search ( $value, $current_values );
293
+ if (! is_null ( $pos )) {
294
+ unset ( $current_values [$pos] );
295
+ if (empty ( $current_values )) {
296
+ $pos = array_search ( $filter, $filters );
297
+ unset ( $filters [$pos] );
298
+ } else {
299
+ $filter->set_values ( $current_values );
300
+ }
301
+ }
302
+ }
303
+ $copy->filter = $filters;
304
  }
305
+
306
  return $this->auto_set_from ? $copy->set_from(AfsOrigin::FACET) : $copy;
307
  }
308
+
309
+ /** @brief Remove existing value from specific facet.
310
+ * @remark No error is reported when the removed @a value is not already set.
311
+ * @param $facet_id [in] id of the facet to update.
312
+ * @param $value [in] value to be removed from the list of values associated
313
+ * to the facet.
314
+ * @return new up to date instance.
315
+ */
316
+ public function remove_filter_on_feed($facet_id, $value, $feed=null)
317
+ {
318
+ $copy = $this->copy();
319
+ $copy = $copy->on_assignment();
320
+
321
+ if (($f = $copy->get_feed ( $feed )) != null) {
322
+ $f->remove_filter ( $facet_id, $value );
323
+ }
324
+
325
+ return $this->auto_set_from ? $copy->set_from(AfsOrigin::FACET) : $copy;
326
+ }
327
+
328
+ /**
329
+ * @brief set a new geolocation filter (replacing existing one) using a center point and a range.
330
+ * @param $lat the center point latitude
331
+ * @param $lon the center point longitude
332
+ * @param int $range the range used to filter
333
+ * @param string $lat_facet_id the facet id used to compare latitudes
334
+ * @param string $lon_facet_id the facet id used to compare longitude
335
+ * @return new up to date instance
336
+ */
337
+ public function set_geoDist_filter($lat, $lon, $range, $lat_facet_id='geo:lat', $lon_facet_id='geo:long') {
338
+ $copy =$this->copy();
339
+ // remove existing geoDist filter
340
+ $copy->remove_native_function_filter(AfsNativeFunction::Geo_dist);
341
+
342
+ // create the filter
343
+ $filter = native_function_filter(AfsNativeFunction::Geo_dist, array($lat,$lon,$lat_facet_id,$lon_facet_id));
344
+ // add operator and operand
345
+ $filter = $filter->less->value($range);
346
+ // set the new filter
347
+ $copy->set_native_function_filter($filter);
348
+ return $copy;
349
+ }
350
+
351
+ /**
352
+ * @brief remove geolocation filter if exists
353
+ * @return new up to date instance
354
+ */
355
+ public function remove_geoDist_filter() {
356
+ $copy = $this->copy();
357
+ $copy->remove_native_function_filter(AfsNativeFunction::Geo_dist);
358
+ return $copy;
359
+ }
360
+
361
+ /**
362
+ * @param $lat
363
+ * @param $lon
364
+ * @param string $lat_facet_id
365
+ * @param string $lon_facet_id
366
+ * @return copy
367
+ */
368
+ public function set_geoDist_sort($lat, $lon, $order=AfsSortOrder::DESC, $lat_facet_id='geo:lat', $lon_facet_id='geo:long') {
369
+ $copy = $this->copy();
370
+ // create the filter
371
+ $sort = AfsNativeFunction::Geo_dist . '(' . $lat . ',' . $lon . ',' . $lat_facet_id . ',' . $lon_facet_id . ')' . ',' . $order;
372
+
373
+
374
+ $copy->set_native_function_sort($sort);
375
+
376
+ return $copy;
377
+ }
378
+
379
  /** @brief Check whether instance has a @a value associated with specified
380
  * facet id.
381
  * @param $facet_id [in] id of the facet to check.
382
  * @param $value [in] value to check in the list of values for the given
383
  * @a facet_id.
384
+ * @param $feed [in] the feed name. If no set, filter is set on all feed.
385
  * @return true when the @a value is present in the list of values
386
  * associated with @a facet_id, false otherwise. Always false when provided
387
  * @a facet_id is unknown.
388
  */
389
+ public function has_filter($facet_id, $value, $feed=null)
390
  {
391
+ if (! is_null($feed) && ! is_null($this->feed)) {
392
+ foreach ($this->feed as $f) {
393
+ if ($f->get_name() === $feed) {
394
+ return $f->has_filter($facet_id, $value);
395
+ }
396
+ }
397
+ return false;
398
+ } elseif (! is_null($feed)) {
399
  return false;
400
  } else {
401
+ foreach ($this->filter as $filter) {
402
+ if ($filter->get_facet_id() === $facet_id) {
403
+ return in_array($value, $filter->get_values());
404
+ }
405
+ }
406
+ return false;
407
  }
408
  }
409
  /** @brief Retrieve the list of values for specific facet id.
410
  * @remark You should ensure that the required @a facet_id is valid.
411
  * @param $facet_id [in] facet id to consider.
412
+ * @param $feed [in] the feed name. If not set, filter values applied on all feeds will be returned.
413
  * @return list of values associated to the given @a facet_id.
414
  */
415
+ public function get_filter_values($facet_id, $feed=null)
416
  {
417
+ if (! is_null($feed) && ! is_null($this->feed)) {
418
+ foreach($this->feed as $f) {
419
+ if ($f->get_name() === $feed) {
420
+ return $f->get_filter_values($facet_id);
421
+ }
422
+ }
423
+ throw new AfsFilterException("$facet_id doesn't exist");
424
+ } elseif (! is_null($feed)) {
425
+ throw new AfsFilterException("$facet_id doesn't exist");
426
+ } else {
427
+ foreach ($this->filter as $filter) {
428
+ if ($filter->get_facet_id() === $facet_id) {
429
+ return $filter->get_values();
430
+ }
431
+ }
432
+ throw new AfsFilterException("$facet_id doesn't exist");
433
  }
 
434
  }
435
  /** @brief Retrieve the list of all managed facet ids.
436
  *
437
  * Only elements from this list should be used to query @a get_filter_values
438
  * method.
439
+ * @param @feed [in] the feed name. If not set return all filter not set on feed.
440
  * @return list of facet ids.
441
  */
442
+ public function get_filters($feed_name=null)
443
  {
444
+ $facet_ids = array();
445
+ if ($feed_name==null) {
446
+ foreach ($this->filter as $filter) {
447
+ $facet_ids[] = $filter->get_facet_id();
448
+ }
449
+ foreach ($this->feed as $feed) {
450
+ $facet_ids = array_merge($facet_ids, $feed->get_facet_ids());
451
+ }
452
+ } else {
453
+ foreach ($this->feed as $feed) {
454
+ if ($feed->get_name() === $feed_name) {
455
+ $facet_ids = array_merge($facet_ids, $feed->get_facet_ids());
456
+ }
457
+ }
458
+
459
+ }
460
+
461
+ return $facet_ids;
462
  }
463
  /** @} */
464
 
517
  * @{ */
518
 
519
  /** @brief Check whether reply page is set.
520
+ * @param @feed [in] the feed name. If not set check if default page is set.
521
  * @return always true.
522
  */
523
+ public function has_page($feed=null)
524
  {
525
+ return $this->has_parameter('page', $feed);
526
  }
527
  /** @brief Define new result page.
528
  * @param $page [in] result page to output. It should be greater than or
529
  * equal to 1.
530
+ * @param $feed [in] the feed to set the page on. Default behavior will set the page number for all feeds
531
  * @return new up to date instance.
532
+ * @throws Exception on invalid page number.
533
  */
534
+ public function set_page($page, $feed=null)
535
  {
536
  if ($page <= 0)
537
  {
538
  throw new Exception('Invalid page number: ' . $page);
539
  }
540
+
541
  $copy = $this->copy();
542
+ is_null($assignment_res = $copy->on_assignment()) ? null : $copy = $assignment_res;
543
+
544
+ $copy->set_parameter('page', (int) $page, $feed);
545
+
546
  return $this->auto_set_from ? $copy->set_from(AfsOrigin::PAGER) : $copy;
547
  }
548
  /** @brief Retrieve current reply page.
549
+ * @param $feed [in] the feed name. If not set the default page will be returned (used when feed is not specified, see AfsQuery::set_page)
550
+ * @remark For a new query, this value is reset to 1.
551
  * @return reply page number.
552
  */
553
+ public function get_page($feed=null)
554
  {
555
+ return $this->get_parameter('page', $feed);
556
  }
557
  /** @brief Shortcut for @a set_page(1).
558
  *
560
  */
561
  protected function reset_page()
562
  {
563
+ $this->set_parameter('page', 1);
564
+ return $this;
565
  }
566
  /** @} */
567
 
612
  /** @brief Checks whether sort parameter is set.
613
  * @param $name [in] check this specific parameter name (default=null:
614
  * checks whether at least one sort parameter is set).
615
+ * @param $feed [in] the feed name. If not set, check if sort in set for all feeds.
616
  * @return true when sort parameter is set, false otherwise.
617
  */
618
+ public function has_sort($name = null, $feed = null)
619
  {
620
+ if (!is_null($feed)) {
621
+ $f = $this->get_feed($feed);
622
+ if (!is_null($f)) {
623
+ $sort_list = $f->get_sorts();
624
+ } else {
625
+ $sort_list = array();
626
+ }
627
+ } else {
628
+ $sort_list = $this->sort;
629
+ }
630
+
631
  if (is_null($name)) {
632
+ return !empty($sort_list);
633
  } else {
634
+ foreach ($sort_list as $sort) {
635
+ if ($sort->get_key() === $name)
636
+ return true;
637
+ }
638
+ return false;
639
  }
640
  }
641
+
642
  /** @brief Resets sort order to AFS default sort order.
643
  */
644
  public function reset_sort()
655
  * @a reset_sort.
656
  * @param $order [in] order applied to the given parameter. Allowed values
657
  * are AfsSortOrder::DESC (default) or AfsSortOrder:ASC.
658
+ * @param @feed [in] the feed name. If not set, sort is set for all feeds.
659
  * @exception Exception when provided sort parameter does not conform to
660
  * required syntax.
661
  */
662
+ public function set_sort($sort_param, $order=AfsSortOrder::DESC, $feed=null)
663
  {
664
+ $copy = $this->copy();
665
+ $copy = $copy->on_assignment();
666
+
667
+ if (! is_null($feed) && ! is_null(($f = $copy->get_feed($feed)))) {
668
+ $f->set_sort($sort_param, $order);
669
+ } elseif (! is_null($feed)) {
670
+ $f = new AfsFeed($feed, false);
671
+ $f->add_sort($sort_param, $order);
672
+ $copy->feed[] = $f;
673
+ } else {
674
+ $copy->internal_add_sort($this->sort, $sort_param, $order);
675
+ }
676
+
677
+ return $copy;
678
  }
679
  /** @brief Defines additional sort order.
680
  *
687
  * @a reset_sort.
688
  * @param $order [in] order applied to the given parameter. Allowed values
689
  * are AfsSortOrder::DESC (default) or AfsSortOrder:ASC.
690
+ * @param @feed [in] the feed name. If not set, sort is add for all feeds.
691
  * @exception Exception when provided sort parameter does not conform to
692
  * required syntax.
693
  */
694
+ public function add_sort($sort_param, $order=AfsSortOrder::DESC, $feed=null)
695
  {
696
+ $copy = $this->copy();
697
+ $copy = $copy->on_assignment();
698
+
699
+ if (! is_null($feed) && ! is_null(($f = $copy->get_feed($feed)))) {
700
+ $f->add_sort($sort_param, $order);
701
+ } elseif (! is_null($feed)) {
702
+ $f = new AfsFeed($feed, false);
703
+ $f->add_sort($sort_param, $order);
704
+ } else {
705
+ $copy->internal_add_sort($this->sort, $sort_param, $order);
706
+ }
707
+
708
+ return $copy;
709
  }
710
  /** @brief Retrieves sort order.
711
  * @deprecated This method will be removed soon!
712
+ * @param @feed [in] the feed name. If not set, sort for all feed is return.
713
  * @return sort order as string.
714
  */
715
+ public function get_sort($feed=null)
716
  {
717
  $result = '';
718
  $sorts = array();
719
+
720
+ if (! is_null($feed) && ! is_null(($f = $this->get_feed($feed)))) {
721
+ $result = $f->get_sort();
722
+ } else {
723
+ foreach ($this->sort as $sort) {
724
+ $sorts[] = $sort->format();
725
+ }
726
+ if (!empty($sorts)) {
727
+ $result = implode(';', $sorts);
728
+ }
729
  }
730
  return $result;
731
  }
732
  /** @brief Retrieves sort order of the specified parameter.
733
  * @param $name [in] parameter name to check.
734
+ * @param @feed [in] the feed name. If not set, sort order for all feeds is return.
735
  * @return AfsSortOrder::ASC or AfsSortOrder::DESC.
736
  * @exception OutOfBoundsException when required sort parameter is not
737
  * defined.
738
  */
739
+ public function get_sort_order($name, $feed=null)
740
  {
741
+ if (! is_null($feed)) {
742
+ if (! is_null(($f = $this->get_feed($feed)))) {
743
+ $sort_list = $f->get_sorts();
744
+ }
745
  } else {
746
+ $sort_list = $this->sort;
747
  }
748
+
749
+ foreach ($sort_list as $sort) {
750
+ if ($sort->get_key() === $name) {
751
+ return $sort->get_sort_order();
752
+ }
753
+ }
754
+ throw new OutOfBoundsException('Unknown sort parameter: ' . $name);
755
  }
756
+
757
  /** @brief Adds new sort parameter or substitutes existing one.
758
  *
759
  * @param $current_value [in] current sort order value.
762
  *
763
  * @return copy of current query.
764
  */
765
+ private function internal_add_sort($current_value, $sort_param, $order, $feed=null)
766
  {
767
  if ($sort_param == '') {
768
  $sort_param = null;
776
  AfsSortOrder::check_value($order, 'Invalid sort order provided: ');
777
 
778
  $new_value = $current_value;
779
+ if (is_null($new_value)) {
780
+ $new_value = array();
781
+ }
782
+
783
+ $new_value[] = new AfsSortParameter($sort_param, $order, $feed);
784
  } else {
785
  $new_value = array();
786
  }
787
 
788
+ $this->sort = $new_value;
 
 
 
789
  }
790
  /** @} */
791
 
809
  public function set_cluster($facet_id, $replies_per_cluster)
810
  {
811
  $copy = $this->copy();
812
+ $copy = $copy->on_assignment();
813
+ $copy->cluster = new AfsClusterParameter($facet_id, $replies_per_cluster);
814
  return $copy;
815
  }
816
  /** @brief Unsets cluster definition.
831
  */
832
  public function get_cluster_id()
833
  {
834
+ $this->check_cluster_initialization();
835
+ return $this->cluster->get_facet_id();
836
  }
837
  /** @brief Retrieves maximum number of replies per cluster.
838
  * @return Number of replies per cluster reply.
840
  */
841
  public function get_nb_replies_per_cluster()
842
  {
843
+ $this->check_cluster_initialization();
844
+ return $this->cluster->get_value();
845
  }
846
  /** @internal
847
  * @brief Split cluster property to retrieve facet id and nb replies per cluster.
849
  private function get_splitted_cluster_definition()
850
  {
851
  $this->check_cluster_initialization();
852
+ return explode(',', $this->cluster->format());
853
  }
854
  /** @brief Checks whether number of cluster is limited.
855
  *
868
  {
869
  $this->check_cluster_initialization();
870
  $copy = $this->copy();
871
+ $copy = $copy->on_assignment();
872
  $copy->maxClusters = $max_nb_of_clusters;
873
  return $copy;
874
  }
920
  * @return Current count mode. AfsCount::DOCUMENTS, AfsCount::CLUSTERS or
921
  * @c null when no specific count mode has been set.
922
  */
923
+ public function get_count_mode($feed=null)
924
  {
925
+ return $this->get_parameter('count', $feed);
926
  }
927
  /** @brief Defines new count mode.
928
  *
932
  *
933
  * @return new up to date instance.
934
  */
935
+ public function set_count($count_mode, $feed=null)
936
  {
937
  $this->check_cluster_initialization();
938
  if (!is_null($count_mode))
939
  AfsCount::check_value($count_mode, 'Invalid count mode: ');
940
  $copy = $this->copy();
941
+ is_null($assignment_res = $copy->on_assignment()) ? null : $copy = $assignment_res;
942
+
943
+ $copy->set_parameter('count', $count_mode, $feed);
944
+
945
  return $copy;
946
  }
947
  /** @internal
972
  foreach ($params as $param => $values) {
973
  $adder = 'add_' . $param;
974
  $setter = 'set_' . $param;
975
+ if (strpos($param, 'filter') !== false) {
976
+ $filter_array = explode('@', $param);
977
+ if (count($filter_array) === 2)
978
+ $feed = $filter_array[1];
979
+ else
980
+ $feed = null;
981
  foreach ($values as $filter => $filter_values) {
982
  foreach ($filter_values as $value) {
983
+ if ( ! is_null($feed))
984
+ $result = $result->add_filter_on_feed($filter, array($value), $feed);
985
+ else
986
+ $result = $result->add_filter($filter, $value, $feed);
987
  }
988
  }
989
  } elseif ($param == 'sort') {
1001
  $result->set_custom_parameter($param, $values);
1002
  }
1003
  }
1004
+ $result->page->set_value($page);
1005
  return $result;
1006
  }
1007
 
1009
  {
1010
  $result = new AfsQuery();
1011
  if (array_key_exists('cluster', $params)) {
1012
+ list($facet_id, $nb_replies_per_cluster) = explode(',', $params['cluster']);
1013
+ $cluster_setter = 'set_cluster';
1014
+ $result = $result->$cluster_setter($facet_id, $nb_replies_per_cluster);
1015
  unset($params['cluster']);
1016
  }
1017
  if (array_key_exists('page', $params)) {
1018
+ $page_setter = 'set_page';
1019
+ $result = $result->$page_setter($params['page']);
1020
  unset($params['page']);
1021
  }
1022
  return $result;
1025
 
1026
  protected function get_relevant_parameters()
1027
  {
1028
+ $params = array('filter', 'sort', 'cluster', 'maxClusters', 'overspill', 'count', 'ftsDefault', 'clientData');
1029
+
1030
+ if (! is_null($this->page) && $this->page->get_value() != 1)
1031
  $params[] = 'page';
1032
+
1033
  if (! is_null($this->lang->lang))
1034
  $params[] = 'lang';
1035
  return $params;
1037
 
1038
  protected function get_additional_parameters()
1039
  {
1040
+ return array('facetDefault', 'advancedFilter', 'nativeFunctionFilter', 'nativeFunctionSort');
1041
  }
1042
  /** @} */
1043
 
1127
  return $copy;
1128
  }
1129
 
1130
+ /** @brief Defines sort order for all facet values.
1131
+ *
1132
+ * AFS search default sort for facet values is alphanumeric. This method
1133
+ * allows to change this behaviour.
1134
+ * @remark This configuration is not exposed to AfsQueryCoder.
1135
+ *
1136
+ * @param $mode [in] Sort mode (see AfsFacetValuesSortMode).
1137
+ * @param $order [in] Sort order (see AfsSortOrder).
1138
+ *
1139
+ * @exception InvalidArgumentException when $mode or $order is invalid.
1140
+ */
1141
+ public function set_facet_values_sort_order($facet_id, $mode, $order)
1142
+ {
1143
+ $copy = $this->copy();
1144
+ $copy->facet_mgr->set_facet_values_sort_order($facet_id, $mode, $order);
1145
+ return $copy;
1146
+ }
1147
+
1148
  /** @brief Defines maximum number of facet values replied per facet.
1149
  *
1150
  * Default maximum value is 1000.
1174
  }
1175
  /** @brief Defines multi-selection mode for one or more facets.
1176
  *
1177
+ * Default facet behavior is OR_MODE => see AfsFacetMode::OR_MODE for more details.
1178
+ * If $and_mode is set to true, facet behavior is STICKY_AND_MODE => see AfsFacetMode::STICKY_AND_MODE for more details.
1179
  *
1180
  * @remark Parameters: one (string) or more facet identifiers (individual
1181
  * strings or array of strings).
1182
  */
1183
+ public function set_multi_selection_facets($ids, $and_mode=false)
1184
  {
1185
  $args = get_function_args_as_array(func_get_args());
1186
+ $and_mode = false;
1187
+ if (is_bool(end($args)))
1188
+ $and_mode = array_pop($args);
1189
+
1190
+ if ($and_mode) {
1191
+ $mode = AfsFacetMode::STICKY_AND_MODE;
1192
+ }
1193
+ else {
1194
+ $mode = AfsFacetMode::OR_MODE;
1195
+ }
1196
+
1197
  $copy = $this->copy();
1198
+ $copy->facet_mgr->set_facets_mode($mode, $args);
1199
  return $copy;
1200
  }
1201
+
1202
  /** @brief Defines mono-selection mode for one or more facets.
1203
  *
1204
  * See AfsSearch::set_default_mono_selection_facets or
1214
  $copy->facet_mgr->set_facets_mode(AfsFacetMode::SINGLE_MODE, $args);
1215
  return $copy;
1216
  }
1217
+ /** @brief Defines Full Text Search mode
1218
+ *
1219
+ *
1220
+ * @param $ftsDefault Full Text Search mode
1221
+ */
1222
+ public function set_fts_default($ftsDefault)
1223
+ {
1224
+ AfsFtsMode::check_value($ftsDefault, "Invalid Full Text Search mode: ");
1225
+ $this->ftsDefault = $ftsDefault;
1226
+ }
1227
+ /** @brief Defines id or array of ids of client data to retrieve
1228
+ * This method overwrite any id set before
1229
+ * @param $id id or array of ids of client data
1230
+ */
1231
+ public function set_client_data($id)
1232
+ {
1233
+ if (is_array($id)) {
1234
+ $this->clientData = $id;
1235
+ } else {
1236
+ $this->clientData = array($id);
1237
+ }
1238
+ }
1239
+ /**
1240
+ * @brief Adds id or array of ids of client data to retrieve
1241
+ * @param $id id or array of ids of client data
1242
+ */
1243
+ public function add_client_data($id)
1244
+ {
1245
+ if (is_array($id)) {
1246
+ $this->clientData = array_merge($this->clientData, $id);
1247
+ } else {
1248
+ array_push($this->clientData, $id);
1249
+ }
1250
+ }
1251
  /** @} */
1252
  }
1253
 
lib/antidot/AFS/SEARCH/afs_query_coder.php CHANGED
@@ -5,102 +5,127 @@ require_once 'AFS/SEARCH/afs_feed_coder.php';
5
  require_once 'AFS/SEARCH/afs_sort_coder.php';
6
  require_once 'AFS/SEARCH/afs_query.php';
7
 
8
- /** @brief Default query coder implementation. */
9
- class AfsQueryCoder implements AfsQueryCoderInterface
10
- {
11
- private $path = null;
12
- private $feed_coder = null;
13
- private $filter_coder = null;
14
- private $sort_coder = null;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
 
16
- /** @brief Construct new instance.
17
- * @param $path [in] base path used to generate appropriate link (see
18
- * @a generate_link method). If this parameter is not provided, value
19
- * of $_SERVER['PHP_SELF'] is used as default value.
20
- * @param $feed_coder [in] (optional) feed coder. If not set, default
21
- * implementation is used (see @a AfsFeedCoder).
22
- * @param $filter_coder [in] (optional) filter coder. If not set, default
23
- * implementation is used (see @a AfsFilterCoder).
24
- * @param $sort_coder [in] (optional) sort parameters coder. If not set,
25
- * default implementation is used (see @a AfsSortCoder).
26
- */
27
- public function __construct($path=null, AfsCoderInterface $feed_coder=null,
28
- AfsCoderInterface $filter_coder=null, AfsCoderInterface $sort_coder=null)
29
- {
30
- if (is_null($path))
31
- $path = $_SERVER['PHP_SELF'];
32
- if (is_null($feed_coder))
33
- $feed_coder = new AfsFeedCoder();
34
- if (is_null($filter_coder))
35
- $filter_coder = new AfsFilterCoder();
36
- if (is_null($sort_coder))
37
- $sort_coder = new AfsSortCoder();
38
- $this->path = $path;
39
- $this->feed_coder = $feed_coder;
40
- $this->filter_coder = $filter_coder;
41
- $this->sort_coder = $sort_coder;
42
- }
43
-
44
- /** @brief Generate URL parameters from @a AfsQuery.
45
- * @param $query [in] query to transform to URL parameters.
46
- * @return appropriate URL parameters representing input @a query.
47
- */
48
- public function generate_parameters(AfsQuery $query)
49
- {
50
- $result = array();
51
- foreach ($query->get_parameters(false) as $param => $values) {
52
- $result[] = $param . '=' . htmlspecialchars(urlencode(
53
- $this->coder($param, $values, 'encode')));
54
- }
55
- return implode('&', $result);
56
- }
57
-
58
- /** @brief Convenient method to build link.
59
- *
60
- * Combine @a path parameter to result of @a generate_parameters call.
61
- *
62
- * @param $query [in] @a AfsQuery used to generate appropriate link.
63
- * @return link which can be directly used to query AFS search engine.
64
- */
65
- public function generate_link(AfsQuery $query)
66
- {
67
- return $this->path . '?' . $this->generate_parameters($query);
68
- }
69
-
70
- /** @brief Generate query from URL parameters.
71
- * @param $params [in] array of parameters. Usually set to $_GET.
72
- * @return @a AfsQuery correctly initialized.
73
- */
74
- public function build_query(array $params)
75
- {
76
- $buffer = array();
77
- foreach ($params as $param => $values) {
78
- $buffer[$param] = $this->coder($param, $values, 'decode');
79
- }
80
- $query = AfsQuery::create_from_parameters($buffer);
81
- return $query;
82
- }
83
-
84
- /** @internal
85
- * @brief Encode/decode provided values.
86
- *
87
- * If necessary coder exists, it is used to encode/decode provided
88
- * @a values. Otherwise, @a values parameter is returned as is.
89
- *
90
- * @param $param_name [in] name of parameter to work on.
91
- * @param $values [in] one or multiple values to encode/decode.
92
- * @param $action [in] @c encode or @c decode (see interface
93
- * @a AfsCoderInterface).
94
- *
95
- * @return encode/decode or unmodified values.
96
- */
97
- private function coder($param_name, $values, $action)
98
- {
99
  $coder = $param_name . '_coder';
100
  if (property_exists($this, $coder)) {
101
- return $this->$coder->$action($values);
102
  } else {
103
- return $values;
104
  }
105
  }
106
  }
5
  require_once 'AFS/SEARCH/afs_sort_coder.php';
6
  require_once 'AFS/SEARCH/afs_query.php';
7
 
8
+ /**
9
+ * @brief Default query coder implementation.
10
+ */
11
+ class AfsQueryCoder implements AfsQueryCoderInterface {
12
+ private $path = null;
13
+ private $feed_coder = null;
14
+ private $filter_coder = null;
15
+ private $sort_coder = null;
16
+
17
+ /**
18
+ * @brief Construct new instance.
19
+ *
20
+ * @param $path [in]
21
+ * base path used to generate appropriate link (see
22
+ * @a generate_link method). If this parameter is not provided, value
23
+ * of $_SERVER['PHP_SELF'] is used as default value.
24
+ * @param $feed_coder [in]
25
+ * (optional) feed coder. If not set, default
26
+ * implementation is used (see @a AfsFeedCoder).
27
+ * @param $filter_coder [in]
28
+ * (optional) filter coder. If not set, default
29
+ * implementation is used (see @a AfsFilterCoder).
30
+ * @param $sort_coder [in]
31
+ * (optional) sort parameters coder. If not set,
32
+ * default implementation is used (see @a AfsSortCoder).
33
+ */
34
+ public function __construct($path = null, AfsCoderInterface $feed_coder = null, AfsCoderInterface $filter_coder = null, AfsCoderInterface $sort_coder = null) {
35
+ if (is_null ( $path ))
36
+ $path = $_SERVER ['PHP_SELF'];
37
+ if (is_null ( $feed_coder ))
38
+ $feed_coder = new AfsFeedCoder ();
39
+ if (is_null ( $filter_coder ))
40
+ $filter_coder = new AfsFilterCoder ();
41
+ if (is_null ( $sort_coder ))
42
+ $sort_coder = new AfsSortCoder ();
43
+ $this->path = $path;
44
+ $this->feed_coder = $feed_coder;
45
+ $this->filter_coder = $filter_coder;
46
+ $this->sort_coder = $sort_coder;
47
+ }
48
+
49
+ /**
50
+ * @brief Generate URL parameters from @a AfsQuery.
51
+ *
52
+ * @param $query [in]
53
+ * query to transform to URL parameters.
54
+ * @return appropriate URL parameters representing input @a query.
55
+ */
56
+ public function generate_parameters(AfsQuery $query) {
57
+ $result = array ();
58
+ foreach ( $query->get_parameters ( false ) as $param => $values ) {
59
+ $result [] = $param . '=' . htmlspecialchars ( urlencode ( $this->coder ( $param, $values, 'encode' ) ) );
60
+ }
61
+ return implode ( '&', $result );
62
+ }
63
+
64
+ /**
65
+ * @brief Convenient method to build link.
66
+ *
67
+ * Combine @a path parameter to result of @a generate_parameters call.
68
+ *
69
+ * @param $query [in]
70
+ * @a AfsQuery used to generate appropriate link.
71
+ * @return link which can be directly used to query AFS search engine.
72
+ */
73
+ public function generate_link(AfsQuery $query) {
74
+ return $this->path . '?' . $this->generate_parameters ( $query );
75
+ }
76
+
77
+ /**
78
+ * @brief Generate query from URL parameters.
79
+ *
80
+ * @param $params [in]
81
+ * array of parameters. Usually set to $_GET.
82
+ * @return @a AfsQuery correctly initialized.
83
+ */
84
+ public function build_query(array $params) {
85
+ $buffer = array ();
86
+ foreach ( $params as $param => $values ) {
87
+ $buffer [$param] = $this->coder ( $param, $values, 'decode' );
88
+ }
89
+ $query = AfsQuery::create_from_parameters ( $buffer );
90
+ return $query;
91
+ }
92
+
93
+ /**
94
+ * @internal
95
+ * @brief Encode/decode provided values.
96
+ *
97
+ * If necessary coder exists, it is used to encode/decode provided
98
+ * @a values. Otherwise, @a values parameter is returned as is.
99
+ *
100
+ * @param $param_name [in]
101
+ * name of parameter to work on.
102
+ * @param $values [in]
103
+ * one or multiple values to encode/decode.
104
+ * @param $action [in]
105
+ * @c encode or @c decode (see interface
106
+ * @a AfsCoderInterface).
107
+ *
108
+ * @return encode/decode or unmodified values.
109
+ */
110
+ private function coder($param_name, $values, $action) {
111
+ $param_name = explode( '@', $param_name );
112
+ $param_name = $param_name [0];
113
+ $coder = $param_name . '_coder';
114
+ if (property_exists ( $this, $coder )) {
115
+ return $this->$coder->$action ( $values );
116
+ } else {
117
+ return $values;
118
+ }
119
+ }
120
 
121
+ public function get_separator($param) {
122
+ $param = explode( '@', $param );
123
+ $param_name = $param [0];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
124
  $coder = $param_name . '_coder';
125
  if (property_exists($this, $coder)) {
126
+ return $this->$coder->get_separator();
127
  } else {
128
+ return ',';
129
  }
130
  }
131
  }
lib/antidot/AFS/SEARCH/afs_reply_helper.php CHANGED
@@ -66,6 +66,27 @@ class AfsReplyHelper extends AfsBaseReplyHelper
66
  {
67
  return $this->get_clientdatas()->get_clientdata($id);
68
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
  }
70
 
71
 
66
  {
67
  return $this->get_clientdatas()->get_clientdata($id);
68
  }
69
+
70
+ /**
71
+ * @brief check if geo data exists in reply set
72
+ * @return bool true if geo data exists, else false
73
+ */
74
+ public function has_geo_data() {
75
+ try {
76
+ return $this->reply->geo_reply_ext != null;
77
+ }
78
+ catch (Exception $e) {
79
+ return false;
80
+ }
81
+ }
82
+
83
+ /**
84
+ * @brief return the geo data field in current reply set
85
+ * @return an array of geo data field values if exists, else null
86
+ */
87
+ public function get_geo_data() {
88
+ return $this->has_geo_data() ? $this->reply->geo_reply_ext : null;
89
+ }
90
  }
91
 
92
 
lib/antidot/AFS/SEARCH/afs_reply_helper_factory.php CHANGED
@@ -2,6 +2,9 @@
2
  require_once "AFS/SEARCH/afs_text_helper.php";
3
  require_once "AFS/SEARCH/afs_reply_helper.php";
4
  require_once "AFS/SEARCH/afs_promote_reply_helper.php";
 
 
 
5
 
6
  /** @brief Factory for reply helper. */
7
  class AfsReplyHelperFactory
@@ -26,7 +29,32 @@ class AfsReplyHelperFactory
26
  public function create($feed, $reply)
27
  {
28
  if ('Promote' == $feed) {
29
- return new AfsPromoteReplyHelper($reply);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  } else {
31
  return new AfsReplyHelper($reply, $this->visitor);
32
  }
2
  require_once "AFS/SEARCH/afs_text_helper.php";
3
  require_once "AFS/SEARCH/afs_reply_helper.php";
4
  require_once "AFS/SEARCH/afs_promote_reply_helper.php";
5
+ require_once "AFS/SEARCH/afs_promote_redirect_reply_helper.php";
6
+ require_once "AFS/SEARCH/afs_promote_banner_reply_helper.php";
7
+ require_once "COMMON/afs_exception.php";
8
 
9
  /** @brief Factory for reply helper. */
10
  class AfsReplyHelperFactory
29
  public function create($feed, $reply)
30
  {
31
  if ('Promote' == $feed) {
32
+ $xmlstring = $reply->clientData[0]->contents;
33
+ $xmlstring = '<promote>' . $xmlstring . '</promote>';
34
+ $clientdata = clone $reply->clientData[0];
35
+ $clientdata->contents = $xmlstring;
36
+
37
+ $xmlclientdata = new AfsXmlClientDataHelper($clientdata);
38
+
39
+
40
+ if ($xmlclientdata instanceof AfsJsonClientDataHelper) {
41
+ $type = $xmlclientdata->get_value('type');
42
+ } elseif ($xmlclientdata instanceof AfsXmlClientDataHelper) {
43
+ $type = $xmlclientdata->get_value('/promote/afs:type', array("afs" => "http://ref.antidot.net/7.3/bo.xsd"));
44
+ }
45
+
46
+ switch($type) {
47
+ case "default":
48
+ return new AfsPromoteReplyHelper($reply);
49
+ case "banner":
50
+ return new AfsPromoteBannerReplyHelper($reply);
51
+ case "redirection":
52
+ return new AfsPromoteRedirectReplyHelper($reply);
53
+ break;
54
+ default:
55
+ throw new AfsUnknowPromoteTypeException($type);
56
+ break;
57
+ }
58
  } else {
59
  return new AfsReplyHelper($reply, $this->visitor);
60
  }
lib/antidot/AFS/SEARCH/afs_replyset_helper.php CHANGED
@@ -42,7 +42,7 @@ class AfsReplysetHelper extends AfsBaseReplysetHelper
42
  $facets = array();
43
  if (property_exists($reply_set, 'facets') && property_exists($reply_set->facets, 'facet')) {
44
  foreach ($reply_set->facets->facet as $facet) {
45
- $helper = new AfsFacetHelper($facet, $query, $config);
46
  $facets[$helper->get_id()] = $helper;
47
  }
48
  }
@@ -73,8 +73,9 @@ class AfsReplysetHelper extends AfsBaseReplysetHelper
73
 
74
  protected function initialize_pager($reply_set, $query, $config)
75
  {
76
- if (property_exists($reply_set, 'pager'))
77
  $this->pager = new AfsPagerHelper($reply_set->pager, $this->meta, $query, $config);
 
78
  }
79
 
80
 
42
  $facets = array();
43
  if (property_exists($reply_set, 'facets') && property_exists($reply_set->facets, 'facet')) {
44
  foreach ($reply_set->facets->facet as $facet) {
45
+ $helper = new AfsFacetHelper($facet, $query, $config, $this->get_meta()->get_feed());
46
  $facets[$helper->get_id()] = $helper;
47
  }
48
  }
73
 
74
  protected function initialize_pager($reply_set, $query, $config)
75
  {
76
+ if (property_exists($reply_set, 'pager')) {
77
  $this->pager = new AfsPagerHelper($reply_set->pager, $this->meta, $query, $config);
78
+ }
79
  }
80
 
81
 
lib/antidot/AFS/SEARCH/afs_response_helper.php CHANGED
@@ -12,7 +12,7 @@ require_once 'COMMON/afs_helper_format.php';
12
 
13
  /** @brief Main helper for AFS search reply.
14
  *
15
- * This helper is intended to be initiliazed with the reply provided by @a
16
  * AfsSearchQueryManager::send. It allows to manage replies of one of the
17
  * available replysets, including facets and pager. Connection and query errors
18
  * are managed in a uniform way to simplify integration.
@@ -33,11 +33,11 @@ class AfsResponseHelper extends AfsResponseHelperBase
33
  * @param $query [in] query which has produced current reply.
34
  * @param $config [in] helper configuration object.
35
  *
36
- * @exception InvalidArgumentException when one of the parameters is
37
  * invalid.
38
  */
39
  public function __construct($response, AfsQuery $query,
40
- AfsHelperConfiguration $config)
41
  {
42
  $query = $query->auto_set_from();
43
  $this->config = $config;
@@ -45,9 +45,10 @@ class AfsResponseHelper extends AfsResponseHelperBase
45
 
46
  if (property_exists($response, 'replySet')) {
47
  $this->has_reply = true;
48
- $us_mgr = $config->get_user_session_manager();
49
- $us_mgr->set_user_id($this->header->get_user_id());
50
- $us_mgr->set_session_id($this->header->get_session_id());
 
51
 
52
  $this->spellcheck_mgr = new AfsSpellcheckManager($query, $config);
53
  $this->concepts = new AfsConceptManager();
@@ -59,15 +60,15 @@ class AfsResponseHelper extends AfsResponseHelperBase
59
  }
60
 
61
  private function initialize_replysets($replysets, AfsQuery $query,
62
- AfsHelperConfiguration $config)
63
  {
64
  foreach ($replysets as $replyset) {
65
  if (property_exists($replyset, 'meta')
66
- && property_exists($replyset->meta, 'producer')) {
67
  $producer = $replyset->meta->producer;
68
  if ($producer == AfsProducer::SEARCH) {
69
  if ('Promote' == $replyset->meta->uri) {
70
- $this->promote = new AfsPromoteReplysetHelper($replyset, $config);
71
  } else {
72
  $replyset_helper = new AfsReplysetHelper($replyset, $query, $config);
73
  $feed = $replyset_helper->get_meta()->get_feed();
@@ -94,12 +95,24 @@ class AfsResponseHelper extends AfsResponseHelperBase
94
  /** @name Replies
95
  * @{ */
96
 
97
- /** @brief Check whether reponse has a reply.
 
98
  * @return true when a reply is available, false otherwise.
99
  */
100
- public function has_replyset()
101
  {
102
- return $this->has_reply && (! empty($this->replysets));
 
 
 
 
 
 
 
 
 
 
 
103
  }
104
  /** @brief Retrieves all replysets.
105
  * @return all defined reply sets.
@@ -141,7 +154,7 @@ class AfsResponseHelper extends AfsResponseHelperBase
141
  public function has_spellcheck()
142
  {
143
  return $this->has_reply and (!is_null($this->spellcheck_mgr))
144
- and $this->spellcheck_mgr->has_spellcheck();
145
  }
146
  /** @brief Retrieves spellchecks from the @a response.
147
  * @return list of @a AfsSpellcheckHelper or formatted spellcheck depending
@@ -179,7 +192,7 @@ class AfsResponseHelper extends AfsResponseHelperBase
179
  public function has_promote()
180
  {
181
  return $this->has_reply and (! is_null($this->promote))
182
- and $this->promote->has_reply();
183
  }
184
  /** @brief Retrieves all promote helpers.
185
  * @return promote replies.
@@ -212,7 +225,7 @@ class AfsResponseHelper extends AfsResponseHelperBase
212
  public function has_concept()
213
  {
214
  return $this->has_reply and (! is_null($this->concepts))
215
- and $this->concepts->has_concept();
216
  }
217
  /** @brief Retrieves all concept helpers.
218
  * @return concept replies.
12
 
13
  /** @brief Main helper for AFS search reply.
14
  *
15
+ * This helper is intended to be initiliazed with the reply provided by @a
16
  * AfsSearchQueryManager::send. It allows to manage replies of one of the
17
  * available replysets, including facets and pager. Connection and query errors
18
  * are managed in a uniform way to simplify integration.
33
  * @param $query [in] query which has produced current reply.
34
  * @param $config [in] helper configuration object.
35
  *
36
+ * @exception InvalidArgumentException when one of the parameters is
37
  * invalid.
38
  */
39
  public function __construct($response, AfsQuery $query,
40
+ AfsHelperConfiguration $config)
41
  {
42
  $query = $query->auto_set_from();
43
  $this->config = $config;
45
 
46
  if (property_exists($response, 'replySet')) {
47
  $this->has_reply = true;
48
+ # remove cookie settings to avoid headers already send error
49
+ #$us_mgr = $config->get_user_session_manager();
50
+ #$us_mgr->set_user_id($this->header->get_user_id());
51
+ #$us_mgr->set_session_id($this->header->get_session_id());
52
 
53
  $this->spellcheck_mgr = new AfsSpellcheckManager($query, $config);
54
  $this->concepts = new AfsConceptManager();
60
  }
61
 
62
  private function initialize_replysets($replysets, AfsQuery $query,
63
+ AfsHelperConfiguration $config)
64
  {
65
  foreach ($replysets as $replyset) {
66
  if (property_exists($replyset, 'meta')
67
+ && property_exists($replyset->meta, 'producer')) {
68
  $producer = $replyset->meta->producer;
69
  if ($producer == AfsProducer::SEARCH) {
70
  if ('Promote' == $replyset->meta->uri) {
71
+ $this->promote = new AfsPromoteReplysetHelper($replyset,$this->config);
72
  } else {
73
  $replyset_helper = new AfsReplysetHelper($replyset, $query, $config);
74
  $feed = $replyset_helper->get_meta()->get_feed();
95
  /** @name Replies
96
  * @{ */
97
 
98
+ /** @brief Check whether reponse has a reply. Possible to check reply for on feed or for all feeds
99
+ * @param $feed name to be checked
100
  * @return true when a reply is available, false otherwise.
101
  */
102
+ public function has_replyset($feed=null)
103
  {
104
+ if ($feed == null)
105
+ return $this->has_reply && (! empty($this->replysets));
106
+ else {
107
+ try {
108
+ $this->get_replyset($feed);
109
+ return true;
110
+ } catch (OutOfBoundsException $e) {
111
+ return false;
112
+ } catch (AfsNoReplyException $e) {
113
+ return false;
114
+ }
115
+ }
116
  }
117
  /** @brief Retrieves all replysets.
118
  * @return all defined reply sets.
154
  public function has_spellcheck()
155
  {
156
  return $this->has_reply and (!is_null($this->spellcheck_mgr))
157
+ and $this->spellcheck_mgr->has_spellcheck();
158
  }
159
  /** @brief Retrieves spellchecks from the @a response.
160
  * @return list of @a AfsSpellcheckHelper or formatted spellcheck depending
192
  public function has_promote()
193
  {
194
  return $this->has_reply and (! is_null($this->promote))
195
+ and $this->promote->has_reply();
196
  }
197
  /** @brief Retrieves all promote helpers.
198
  * @return promote replies.
225
  public function has_concept()
226
  {
227
  return $this->has_reply and (! is_null($this->concepts))
228
+ and $this->concepts->has_concept();
229
  }
230
  /** @brief Retrieves all concept helpers.
231
  * @return concept replies.
lib/antidot/AFS/SEARCH/afs_search.php CHANGED
@@ -56,6 +56,17 @@ class AfsSearch
56
  if (! $this->config->has_query_coder()) {
57
  $this->config->set_query_coder(new AfsQueryCoder());
58
  }
 
 
 
 
 
 
 
 
 
 
 
59
  $this->query = $this->config->get_query_coder()->build_query($_GET);
60
  return $this->query;
61
  }
@@ -136,6 +147,14 @@ class AfsSearch
136
  return $this->config;
137
  }
138
 
 
 
 
 
 
 
 
 
139
  /** @brief Retrieves search engine connector.
140
  * @return AFS search connector.
141
  */
56
  if (! $this->config->has_query_coder()) {
57
  $this->config->set_query_coder(new AfsQueryCoder());
58
  }
59
+ $parameters = array();
60
+ /*foreach (explode('&', urldecode($_SERVER['QUERY_STRING'])) as $param) {
61
+ list($key, $value) = explode('=', $param);
62
+ $separator = $this->config->get_query_coder()->get_separator($key);
63
+ if (array_key_exists($key, $parameters)) {
64
+ $parameters[$key] = $parameters[$key] . $separator . $value;
65
+ } else {
66
+ $parameters[$key] = $value;
67
+ }
68
+ }*/
69
+
70
  $this->query = $this->config->get_query_coder()->build_query($_GET);
71
  return $this->query;
72
  }
147
  return $this->config;
148
  }
149
 
150
+ /** @brief set helper configuration
151
+ * @param $helperConfiguration the new configuration
152
+ */
153
+ public function set_helper_configuration($helperConfiguration)
154
+ {
155
+ $this->config = $helperConfiguration;
156
+ }
157
+
158
  /** @brief Retrieves search engine connector.
159
  * @return AFS search connector.
160
  */
lib/antidot/AFS/SEARCH/afs_search_query_manager.php CHANGED
@@ -64,6 +64,11 @@ class AfsSearchQueryManager
64
  $sticky = $facet_mgr->is_sticky($facet);
65
  if ($default_sticky != $sticky)
66
  $params['afs:facet'][] = $name . ',sticky=' . ($sticky ? 'true' : 'false');
 
 
 
 
 
67
  }
68
  }
69
  if ($facet_mgr->is_facet_order_strict())
@@ -103,31 +108,52 @@ class AfsSearchQueryManager
103
  {
104
  $params = array();
105
  foreach ($query->get_parameters() as $param => $values) {
106
- if ($param == 'filter') {
 
 
 
 
 
 
 
107
  foreach ($values as $facet => $ids)
108
- $this->fill_in_filter($params, $this->format_filter($query, $facet, $ids));
109
- } elseif ($param == 'sort') {
110
- if (! empty($values)) {
111
  foreach ($values as $name => $order) {
112
- $params['afs:sort'][] = $this->format_sort($name, $order);
113
  }
114
  }
115
- } elseif ($param == 'advancedFilter') {
116
  foreach ($values as $value)
117
- $this->fill_in_filter($params, $value);
 
 
 
 
 
 
 
 
118
  } else {
119
- $params['afs:' . $param] = $values;
120
  }
121
  }
122
  $params = array_merge($params, $query->get_custom_parameters());
123
  return $params;
124
  }
125
 
126
- private function fill_in_filter(array& $params, $value)
127
  {
128
- if (! array_key_exists('afs:filter', $params))
129
- $params['afs:filter'] = array();
130
- $params['afs:filter'][] = $value;
 
 
 
 
 
 
131
  }
132
 
133
  /** @internal
@@ -146,9 +172,25 @@ class AfsSearchQueryManager
146
  return $query->get_facet_manager()->get_or_create_facet($name)->join_values($values);
147
  }
148
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
149
  private function format_sort($name, $order)
150
  {
151
- return $name . ',' . $order;
152
  }
153
  }
154
 
64
  $sticky = $facet_mgr->is_sticky($facet);
65
  if ($default_sticky != $sticky)
66
  $params['afs:facet'][] = $name . ',sticky=' . ($sticky ? 'true' : 'false');
67
+ if (! is_null(($sort_order = $facet->get_values_sort_order()))) {
68
+ list($sort, $order) = $sort_order->format();
69
+ $params['afs:facet'][] = $name . ',sort=' . $sort;
70
+ $params['afs:facet'][] = $name . ',order=' . $order;
71
+ }
72
  }
73
  }
74
  if ($facet_mgr->is_facet_order_strict())
108
  {
109
  $params = array();
110
  foreach ($query->get_parameters() as $param => $values) {
111
+ $param_array = explode('@', $param);
112
+ if (count($param_array) === 2)
113
+ $feed = $param_array[1];
114
+ else
115
+ $feed = null;
116
+ $param_name = $param_array[0];
117
+
118
+ if ($param_name =='filter') {
119
  foreach ($values as $facet => $ids)
120
+ $this->fill_in_filter($params, $this->format_filter($query, $facet, $ids), $feed);
121
+ } elseif ($param_name == 'sort') {
122
+ if (!empty($values)) {
123
  foreach ($values as $name => $order) {
124
+ $this->fill_in_sort($params, $this->format_sort($name, $order), $feed);
125
  }
126
  }
127
+ } elseif ($param_name == 'advancedFilter') {
128
  foreach ($values as $value)
129
+ $this->fill_in_filter($params, $value, $feed);
130
+ } elseif ($param_name == 'nativeFunctionFilter') {
131
+ foreach ($values as $value)
132
+ $this->fill_in_filter($params, $value, $feed);
133
+
134
+ } elseif ($param_name == 'nativeFunctionSort') {
135
+ foreach ($values as $value) {
136
+ $params['afs:sort'][] = $value;
137
+ }
138
  } else {
139
+ $this->fill_in_param($params, $param_name, $values, $feed);
140
  }
141
  }
142
  $params = array_merge($params, $query->get_custom_parameters());
143
  return $params;
144
  }
145
 
146
+ private function fill_in_filter(array& $params, $value, $feed=null)
147
  {
148
+ if (is_null($feed)) {
149
+ if (!array_key_exists('afs:filter', $params))
150
+ $params['afs:filter'] = array();
151
+ $params['afs:filter'][] = $value;
152
+ } else {
153
+ if (!array_key_exists('afs:filter@' . $feed, $params))
154
+ $params['afs:filter@' . $feed] = array();
155
+ $params['afs:filter@' . $feed][] = $value;
156
+ }
157
  }
158
 
159
  /** @internal
172
  return $query->get_facet_manager()->get_or_create_facet($name)->join_values($values);
173
  }
174
 
175
+ private function fill_in_param(array& $params, $param_name, $param_value, $feed=null) {
176
+ if (is_null($feed)) {
177
+ $params['afs:' . $param_name] = $param_value;
178
+ } else {
179
+ $params['afs:' . $param_name . '@' . $feed] = $param_value;
180
+ }
181
+ }
182
+
183
+ private function fill_in_sort(array& $params, $value, $feed=null) {
184
+ if (is_null($feed)) {
185
+ $params['afs:sort'][] = $value;
186
+ } else {
187
+ $params['afs:sort' . '@' . $feed][] = $value;
188
+ }
189
+ }
190
+
191
  private function format_sort($name, $order)
192
  {
193
+ return $name . ',' . $order;
194
  }
195
  }
196
 
lib/antidot/AFS/SEARCH/afs_sort_coder.php CHANGED
@@ -83,5 +83,9 @@ class AfsSortCoder extends AfsCoderBase implements AfsCoderInterface
83
  . preg_quote($this->value_sep) . '|' . preg_quote($this->escape)
84
  . ')', '$1', $value);
85
  }
 
 
 
 
86
  }
87
 
83
  . preg_quote($this->value_sep) . '|' . preg_quote($this->escape)
84
  . ')', '$1', $value);
85
  }
86
+
87
+ public function get_separator() {
88
+ return $this->value_sep;
89
+ }
90
  }
91
 
lib/antidot/AFS/SEARCH/afs_sort_parameter.php ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Created by PhpStorm.
4
+ * User: ct
5
+ * Date: 2/9/15
6
+ * Time: 4:48 PM
7
+ */
8
+
9
+ require_once 'AFS/SEARCH/afs_sort_order.php';
10
+
11
+ class AfsSortParameter extends AfsSingleValueParameter {
12
+
13
+ public function __construct($key, $sort, $feed=null) {
14
+ parent::__construct($key, $sort, $feed);
15
+ $this->sort_order = $sort;
16
+ }
17
+
18
+ public function get_sort_order() {
19
+ return $this->value;
20
+ }
21
+
22
+ public function format () {
23
+ return array($this->key => $this->value);
24
+ }
25
+ }
lib/antidot/AFS/afs_connector.php CHANGED
@@ -73,10 +73,13 @@ abstract class AfsConnector extends AfsConnectorBase implements AfsConnectorInte
73
  $parameters['afs:service'] = $this->service->id;
74
  $parameters['afs:status'] = $this->service->status;
75
  $parameters['afs:output'] = 'json,2';
76
- if (array_key_exists('afs:log', $parameters))
77
- $parameters['afs:log'][] = get_api_version();
78
- else
79
- $parameters['afs:log'] = array(get_api_version());
 
 
 
80
  if (array_key_exists('REMOTE_ADDR', $_SERVER)) {
81
  $parameters['afs:ip'] = $_SERVER['REMOTE_ADDR'];
82
  }
73
  $parameters['afs:service'] = $this->service->id;
74
  $parameters['afs:status'] = $this->service->status;
75
  $parameters['afs:output'] = 'json,2';
76
+ if (! array_key_exists('afs:log', $parameters)) {
77
+ $parameters['afs:log'] = array();
78
+ }
79
+
80
+ $parameters['afs:log'][] = get_api_version();
81
+ $parameters['afs:log'][] = 'PHP_VERSION_' . phpversion();
82
+
83
  if (array_key_exists('REMOTE_ADDR', $_SERVER)) {
84
  $parameters['afs:ip'] = $_SERVER['REMOTE_ADDR'];
85
  }
lib/antidot/AFS/afs_feed.php ADDED
@@ -0,0 +1,309 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class AfsFeed {
4
+ protected $parameters;
5
+ protected $filters = array();
6
+ protected $sort = array();
7
+ protected $name;
8
+ protected $activated;
9
+
10
+ public function __construct($name, $activated, array $parameters=null) {
11
+ $this->activated = $activated;
12
+ $this->name = $name;
13
+ is_null($parameters) ? $this->parameters = array() :
14
+ $this->parameters = $parameters;
15
+ }
16
+
17
+ public function copy() {
18
+ $filters = array();
19
+ foreach ($this->filters as $filter) {
20
+ $filters[] = clone $filter;
21
+ }
22
+
23
+ $sorts = array();
24
+ foreach ($this->sort as $sort) {
25
+ $sorts[] = clone $sort;
26
+ }
27
+
28
+ $copy = clone $this;
29
+ $copy->filters = $filters;
30
+ $copy->sort = $sorts;
31
+
32
+ return $copy;
33
+ }
34
+
35
+ /**
36
+ * @return feed name
37
+ */
38
+ public function get_name() {
39
+ return $this->name;
40
+ }
41
+
42
+ /**
43
+ * @return true if feed is activated for this request
44
+ * (eg; will be generate a afs:feed parameter in query string)
45
+ */
46
+ public function is_activated() {
47
+ return $this->activated;
48
+ }
49
+
50
+ /**
51
+ * @brief to set this feed activated for query (eg. afs:feed parameter in query string)
52
+ * @param $activated
53
+ */
54
+ public function set_activated($activated) {
55
+ $this->activated = $activated;
56
+ }
57
+
58
+ /**
59
+ * @brief add a new query parameter to applied on current feed
60
+ * @param $params
61
+ */
62
+ public function add_parameters($params){
63
+ if (!is_array($params)) {
64
+ $params = array($params);
65
+ }
66
+
67
+ $this->parameters = array_merge($this->parameters, $params);
68
+ }
69
+
70
+ /**
71
+ * @brief retrieve a parameter from is key
72
+ * @param $key the key of parameter to get
73
+ * @return the parameter (AfsQueryParameter)if exists, otherwise null
74
+ */
75
+ public function get_parameter($key) {
76
+ foreach ($this->parameters as $parameter) {
77
+ if ($parameter->get_key() === $key) {
78
+ return $parameter;
79
+ }
80
+ }
81
+
82
+ return null;
83
+ }
84
+
85
+ /**
86
+ * @brief add sort parameter on current feed
87
+ * @param $sort_name
88
+ * @param $order
89
+ */
90
+ public function add_sort($sort_name, $order) {
91
+ $this->sort[] = new AfsSortParameter($sort_name, $order);
92
+ }
93
+
94
+ /**
95
+ * @brief check if sort_nmae is set on this feed
96
+ * @param $sort_name
97
+ * @return true if @a $sort_name is set, otherwise false
98
+ */
99
+ public function has_sort($sort_name) {
100
+ foreach ($this->sort as $sort) {
101
+ if ($sort->get_key() === $sort_name) {
102
+ return true;
103
+ }
104
+ }
105
+ return false;
106
+ }
107
+
108
+ /**
109
+ * @brief get formated sort string (eg. facetId,sortOrder;facetId1,sortOrder; ...)
110
+ * @return string
111
+ */
112
+ public function get_sort() {
113
+ $result = array();
114
+ foreach ($this->sort as $sort) {
115
+ $result[] = $sort->format();
116
+ }
117
+ return implode(';', $result);
118
+ }
119
+
120
+ /**
121
+ * @brief retrieve sort parameter list
122
+ * @return array
123
+ */
124
+ public function get_sorts() {
125
+ return $this->sort;
126
+ }
127
+
128
+ /**
129
+ * @brief set a new sort parameter, replacing existing one
130
+ * @param array $sort
131
+ */
132
+ public function set_sort($key, $order) {
133
+ $sort_found = false;
134
+ foreach ($this->sort as $sort) {
135
+ if ($sort->get_key() === $key) {
136
+ $sort->set_value($order);
137
+ $sort_found = true;
138
+ break;
139
+ }
140
+ }
141
+
142
+ if (! $sort_found) {
143
+ $this->sort[] = new AfsSortParameter($key, $order);
144
+ }
145
+ }
146
+
147
+ /**
148
+ * @brief check if a filter is set on this feed
149
+ * @param $facet_id
150
+ * @param $value
151
+ * @return true is filter is set, false otherwise
152
+ */
153
+ public function has_filter($facet_id, $value) {
154
+ foreach ($this->filters as $filter) {
155
+ if ($filter->get_facet_id() === $facet_id && in_array($value, $filter->get_values())) {
156
+ return true;
157
+ }
158
+ }
159
+ return false;
160
+ }
161
+
162
+ /**
163
+ * @ add a new filter on this feed
164
+ * @param $facet_id
165
+ * @param $values
166
+ */
167
+ public function add_filter($facet_id, $values) {
168
+ if (! is_array($values))
169
+ $values = array($values);
170
+
171
+ $filter_found = false;
172
+ foreach($this->filters as $filter) {
173
+ if ($filter->get_facet_id() === $facet_id) {
174
+ $filter_found = true;
175
+ foreach ($values as $value) {
176
+ if (! in_array($value, $filter->get_values())) {
177
+ $filter->add_values($value);
178
+ }
179
+ }
180
+ break;
181
+ }
182
+
183
+ }
184
+
185
+ if (! $filter_found) {
186
+ $this->filters[] = new AfsFilterParameter($facet_id, $values);
187
+ }
188
+ }
189
+
190
+ /**
191
+ * @brief remove a filter already set on this feed
192
+ * @param $facet_id
193
+ * @param $value
194
+ */
195
+ public function remove_filter($facet_id, $value) {
196
+ foreach ($this->filters as $filter) {
197
+ if ($filter->get_facet_id() === $facet_id) {
198
+ $values = $filter->get_values();
199
+ if (($pos_value = array_search($value, $values)) !== false) {
200
+ unset($values[$pos_value]);
201
+ if (empty($values)) {
202
+ $pos_filter = array_search($filter, $this->filters);
203
+ unset($this->filters[$pos_filter]);
204
+ } else {
205
+ $filter->set_values($values);
206
+ }
207
+ }
208
+ break;
209
+ }
210
+ }
211
+
212
+ }
213
+
214
+ /**
215
+ * @param $facet_id
216
+ * @throws AfsFilterException
217
+ */
218
+ public function get_filter_values($facet_id) {
219
+ foreach ($this->filters as $filter) {
220
+ if ($filter->get_facet_id() === $facet_id) {
221
+ return $filter->get_values();
222
+ }
223
+ }
224
+ throw new AfsFilterException("$facet_id doesn't exist");
225
+ }
226
+
227
+ /**
228
+ * @param $facet_id
229
+ * @param $values
230
+ */
231
+ public function set_filter($facet_id, $values) {
232
+ if (! is_array($values))
233
+ $values = array($values);
234
+
235
+ $this->filters = array(new AfsFilterParameter($facet_id, $values));
236
+ }
237
+
238
+ /**
239
+ * @return array
240
+ */
241
+ public function get_filters() {
242
+ return $this->filters;
243
+ }
244
+
245
+ /**
246
+ * @return array
247
+ */
248
+ public function get_facet_ids() {
249
+ $result = array();
250
+ foreach ($this->filters as $filter) {
251
+ $result[] = $filter->get_facet_id();
252
+ }
253
+ return $result;
254
+ }
255
+
256
+ /**
257
+ * @param array $filters
258
+ */
259
+ public function set_filters(array $filters) {
260
+ $this->filters = $filters;
261
+ }
262
+
263
+ /**
264
+ * @return mixed
265
+ */
266
+ public function format() {
267
+ return $this->name;
268
+ }
269
+
270
+ /**
271
+ * @return array
272
+ */
273
+ private function get_filter_parameters() {
274
+ $result = array();
275
+ foreach ($this->filters as $filter) {
276
+ $result['filter@' . $this->name][$filter->get_facet_id()] = $filter->get_values();
277
+ }
278
+ return $result;
279
+ }
280
+
281
+ /**
282
+ * @param array $parameter_list
283
+ * @return array
284
+ */
285
+ public function get_parameters(array $parameter_list) {
286
+ $result = array();
287
+ foreach ($this->parameters as $parameter) {
288
+ if (in_array($parameter->get_key(), $parameter_list)) {
289
+ if (is_callable(array($parameter, 'get_value'))) {
290
+ $result[$parameter->get_key() . '@' . $this->name] = $parameter->get_value();
291
+ } elseif (is_callable(array($parameter, 'get_values'))) {
292
+ $result[$parameter->get_key() . '@' . $this->name] = $parameter->get_values();
293
+ }
294
+ }
295
+ }
296
+
297
+ $result = array_merge($result, $this->get_relevent_parameters());
298
+
299
+ return array_merge($result, $this->get_filter_parameters());
300
+ }
301
+
302
+ private function get_relevent_parameters() {
303
+ $page = $this->get_parameter('page');
304
+ if (! is_null($page) && $page->get_value() !== 1) {
305
+ return array('page@' . $this->name => $page->get_value());
306
+ }
307
+ return array();
308
+ }
309
+ }
lib/antidot/AFS/afs_multiple_values_parameter.php ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Created by PhpStorm.
4
+ * User: ct
5
+ * Date: 2/6/15
6
+ * Time: 11:33 AM
7
+ */
8
+
9
+ class AfsMultipleValuesParameter extends AfsQueryParameter
10
+ {
11
+ protected $key;
12
+ protected $values;
13
+
14
+ public function __construct($key, array $values) {
15
+ parent::__construct($key);
16
+ $this->values = $values;
17
+ }
18
+
19
+ /**
20
+ * @brief add a value on current parameter
21
+ * @param $values
22
+ */
23
+ public function add_values($values) {
24
+ if (is_array($values))
25
+ $this->values = array_merge($this->values, $values);
26
+ else
27
+ $this->values[] = $values;
28
+ }
29
+
30
+ /**
31
+ * @brief remove a value on current parameter
32
+ * @param $value
33
+ * @return true is there is more values on current parameter, false otherwise
34
+ */
35
+ public function remove_value($value) {
36
+ if (($key = array_search($value, $this->values)) !== false) {
37
+ unset($this->values[$key]);
38
+ if (empty($this->values))
39
+ return false;
40
+ else
41
+ return true;
42
+ }
43
+ return true;
44
+ }
45
+
46
+ /**
47
+ * @brief set a new list of values on current parameter
48
+ * @param array $values
49
+ */
50
+ public function set_values(array $values) {
51
+ $this->values = $values;
52
+ }
53
+
54
+ /**
55
+ * @brief get all values setted on current parameter
56
+ * @return array of values
57
+ */
58
+ public function get_values()
59
+ {
60
+ return $this->values;
61
+ }
62
+
63
+ /**
64
+ * @brief format this parameter
65
+ * @return array|void
66
+ */
67
+ public function format() {
68
+ return array ($this->key, $this->values);
69
+
70
+ }
71
+ }
lib/antidot/AFS/afs_query_base.php CHANGED
@@ -2,6 +2,9 @@
2
  require_once 'COMMON/afs_user_session_manager.php';
3
  require_once 'COMMON/afs_exception.php';
4
  require_once 'AFS/afs_origin.php';
 
 
 
5
 
6
  /** @brief Represents an AFS query.
7
  *
@@ -14,7 +17,7 @@ abstract class AfsQueryBase
14
  {
15
  protected $feed = array(); // afs:feed
16
  protected $query = null; // afs:query
17
- protected $replies = 10; // afs:replies
18
  protected $userId = null; // afs:userId
19
  protected $sessionId = null; // afs:sessionId
20
  protected $log = array(); // afs:log
@@ -31,19 +34,29 @@ abstract class AfsQueryBase
31
  public function __construct(AfsQueryBase $afs_query=null)
32
  {
33
  if (is_null($afs_query)) {
34
- $this->userId = uniqid('user_');
35
- $this->sessionId = uniqid('session_');
 
36
  } else {
37
- $this->feed = $afs_query->feed;
38
- $this->query = $afs_query->query;
39
- $this->replies = $afs_query->replies;
40
- $this->userId = $afs_query->userId;
41
- $this->sessionId = $afs_query->sessionId;
42
- $this->log = $afs_query->log;
43
- $this->key = $afs_query->key;
44
- $this->from = $afs_query->from;
45
- $this->auto_set_from = $afs_query->auto_set_from;
 
 
 
 
 
 
 
 
46
  $this->custom_parameters = $afs_query->custom_parameters;
 
47
  }
48
  }
49
 
@@ -64,9 +77,22 @@ abstract class AfsQueryBase
64
  /** @brief Checks whether feed parameter is set.
65
  * @return @c true when at least one feed is defined, @c false otherwise.
66
  */
67
- public function has_feed()
68
  {
69
- return ! empty($this->feed);
 
 
 
 
 
 
 
 
 
 
 
 
 
70
  }
71
 
72
  /** @brief Assigns new feed name replacing any existing one.
@@ -75,8 +101,8 @@ abstract class AfsQueryBase
75
  public function set_feed($feed)
76
  {
77
  $copy = $this->copy();
78
- $copy->on_assignment();
79
- $copy->feed = array($feed);
80
  return $copy;
81
  }
82
 
@@ -86,17 +112,43 @@ abstract class AfsQueryBase
86
  public function add_feed($feed)
87
  {
88
  $copy = $this->copy();
89
- $copy->on_assignment();
90
- $copy->feed[] = $feed;
 
 
 
 
 
 
 
 
 
 
 
 
 
91
  return $copy;
92
  }
93
 
 
 
 
 
 
 
 
 
 
94
  /** @brief Retrieves all defined feeds.
95
  * @return defined feeds in array or null when no feed is defined.
96
  */
97
  public function get_feeds()
98
  {
99
- return $this->feed;
 
 
 
 
100
  }
101
  /** @} */
102
 
@@ -106,9 +158,9 @@ abstract class AfsQueryBase
106
  /** @brief Checks whether current instance has a query.
107
  * @return true when a query is defined, false otherwise.
108
  */
109
- public function has_query()
110
  {
111
- return $this->query != null;
112
  }
113
  /** @brief Retrieves the query.
114
  *
@@ -116,9 +168,9 @@ abstract class AfsQueryBase
116
  * query by calling @a has_query.
117
  * @return the query.
118
  */
119
- public function get_query()
120
  {
121
- return $this->query;
122
  }
123
  /** @brief Assigns new query value.
124
  *
@@ -126,11 +178,13 @@ abstract class AfsQueryBase
126
  * @param $new_query [in] query to assign to the instance.
127
  * @return new up to date instance.
128
  */
129
- public function set_query($new_query)
130
  {
131
  $copy = $this->copy();
132
- $copy->on_assignment();
133
- $copy->query = $new_query;
 
 
134
  return $this->auto_set_from ? $copy->set_from(AfsOrigin::SEARCHBOX) : $copy;
135
  }
136
  /** @} */
@@ -141,9 +195,9 @@ abstract class AfsQueryBase
141
  /** @brief Checks whether replies is set.
142
  * @return always true.
143
  */
144
- public function has_replies()
145
  {
146
- return $this->replies != null;
147
  }
148
  /** @brief Defines new number of replies.
149
  * @param $replies_nb [in] requested number of replies. It should be
@@ -151,21 +205,21 @@ abstract class AfsQueryBase
151
  * @return new up to date instance.
152
  * @exception Exception on invalid replies number provided.
153
  */
154
- public function set_replies($replies_nb)
155
  {
156
- if ($replies_nb < 0)
157
- throw new Exception('Invalid number of replies: ' . $replies_nb);
158
  $copy = $this->copy();
159
- $copy->on_assignment();
160
- $copy->replies = $replies_nb;
161
- return $copy;
 
 
162
  }
163
  /** @brief Get number of replies per page.
164
  * @return number of replies per reply page.
165
  */
166
- public function get_replies()
167
  {
168
- return $this->replies;
169
  }
170
  /** @} */
171
 
@@ -192,18 +246,18 @@ abstract class AfsQueryBase
192
  * @return current instance.
193
  * @exception Exception when provided origin value is invalid.
194
  */
195
- public function set_from($from)
196
  {
197
  AfsOrigin::check_value($from, 'Invalid query origin: ');
198
- $this->from = $from;
199
  return $this;
200
  }
201
  /** @brief Retrieves origin of the query.
202
  * @return origin of the query.
203
  */
204
- public function get_from()
205
  {
206
- return $this->from;
207
  }
208
  /** @} */
209
 
@@ -220,7 +274,7 @@ abstract class AfsQueryBase
220
  */
221
  public function set_user_id($user_id)
222
  {
223
- $this->userId = $user_id;
224
  return $this;
225
  }
226
  /** @brief Checks whether user id is set.
@@ -236,7 +290,7 @@ abstract class AfsQueryBase
236
  */
237
  public function get_user_id()
238
  {
239
- return $this->userId;
240
  }
241
 
242
  /** @brief Defines session id.
@@ -246,7 +300,7 @@ abstract class AfsQueryBase
246
  */
247
  public function set_session_id($session_id)
248
  {
249
- $this->sessionId = $session_id;
250
  return $this;
251
  }
252
  /** @brief Checks whether session id is set.
@@ -262,7 +316,7 @@ abstract class AfsQueryBase
262
  */
263
  public function get_session_id()
264
  {
265
- return $this->sessionId;
266
  }
267
 
268
  /** @brief Initializes user id and session id.
@@ -324,7 +378,7 @@ abstract class AfsQueryBase
324
  */
325
  public function add_log($value)
326
  {
327
- $this->log[] = $value;
328
  return $this;
329
  }
330
 
@@ -335,7 +389,12 @@ abstract class AfsQueryBase
335
  */
336
  public function get_logs()
337
  {
338
- return $this->log;
 
 
 
 
 
339
  }
340
  /** @} */
341
 
@@ -345,25 +404,25 @@ abstract class AfsQueryBase
345
  /** @brief Checks whether key parameter is set.
346
  * @return True when key parameter is set, false otherwise.
347
  */
348
- public function has_key()
349
  {
350
- return $this->key != null;
351
  }
352
  /** @brief Defines key id.
353
  * @param $key_id [in] Key id to set.
354
  * @return Current instance.
355
  */
356
- public function set_key($key_id)
357
  {
358
- $this->key = $key_id;
359
  return $this;
360
  }
361
  /** @brief Retrieves key value.
362
  * @return Key value.
363
  */
364
- public function get_key()
365
  {
366
- return $this->key;
367
  }
368
  /** @} */
369
 
@@ -390,12 +449,54 @@ abstract class AfsQueryBase
390
  if ($own_param != null && !empty($own_param)) {
391
  if (is_object($own_param) && is_callable(array($own_param, 'format')))
392
  $own_param = $own_param->format();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
393
  $result[$param] = $own_param;
394
  }
395
  }
 
 
396
  return $result;
397
  }
398
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
399
  private function get_aggregated_relevant_parameters()
400
  {
401
  return array_merge(AfsQueryBase::get_relevant_parameters(), $this->get_relevant_parameters());
@@ -413,7 +514,7 @@ abstract class AfsQueryBase
413
  */
414
  protected function get_relevant_parameters()
415
  {
416
- return array_merge(array('replies', 'feed', 'query'), array_keys($this->custom_parameters));
417
  }
418
 
419
  /** @brief Retrieves additional parameters.
@@ -431,7 +532,7 @@ abstract class AfsQueryBase
431
  return $this->custom_parameters;
432
  }
433
 
434
- public function set_custom_parameter($key, $value)
435
  {
436
  $this->custom_parameters[$key] = $value;
437
  }
@@ -442,6 +543,8 @@ abstract class AfsQueryBase
442
  if(property_exists($this, $name)) {
443
  //$name is a field of AfsQueryBase
444
  return $this->$name;
 
 
445
  } else {
446
  if (array_key_exists($name, $this->custom_parameters)) {
447
  //$name is a custom parameter
@@ -451,4 +554,43 @@ abstract class AfsQueryBase
451
  }
452
  }
453
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
454
  }
2
  require_once 'COMMON/afs_user_session_manager.php';
3
  require_once 'COMMON/afs_exception.php';
4
  require_once 'AFS/afs_origin.php';
5
+ require_once 'AFS/afs_single_value_parameter.php';
6
+ require_once 'AFS/afs_multiple_values_parameter.php';
7
+ require_once 'AFS/afs_feed.php';
8
 
9
  /** @brief Represents an AFS query.
10
  *
17
  {
18
  protected $feed = array(); // afs:feed
19
  protected $query = null; // afs:query
20
+ protected $replies = null; // afs:replies
21
  protected $userId = null; // afs:userId
22
  protected $sessionId = null; // afs:sessionId
23
  protected $log = array(); // afs:log
34
  public function __construct(AfsQueryBase $afs_query=null)
35
  {
36
  if (is_null($afs_query)) {
37
+ $this->userId = new AfsSingleValueParameter('userId', uniqid('user_'));
38
+ $this->sessionId = new AfsSingleValueParameter('sessionId', uniqid('session_'));
39
+ $this->replies = new AfsSingleValueParameter('replies', 10);
40
  } else {
41
+ foreach ($afs_query->feed as $feed) {
42
+ $this->feed[] = $feed->copy();
43
+ }
44
+
45
+ if (! is_null($afs_query->query)) $this->query = clone $afs_query->query;
46
+ if (!is_array($afs_query->replies)) $this->replies = clone $afs_query->replies;
47
+ else $this->replies = new AfsSingleValueParameter('replies', 10);
48
+ if (! is_null($afs_query->userId)) $this->userId = clone $afs_query->userId;
49
+ if (! is_null($afs_query->sessionId)) $this->sessionId = clone $afs_query->sessionId;
50
+
51
+ foreach ($afs_query->log as $log) {
52
+ $this->log[] = clone $log;
53
+ }
54
+
55
+ if (! is_null($afs_query->key)) $this->key = clone $afs_query->key;
56
+ if (! is_null($afs_query->from)) $this->from = clone $afs_query->from;
57
+ if (! is_null($afs_query->sessionId)) $this->sessionId = clone $afs_query->sessionId;
58
  $this->custom_parameters = $afs_query->custom_parameters;
59
+ $this->auto_set_from = $afs_query->auto_set_from;
60
  }
61
  }
62
 
77
  /** @brief Checks whether feed parameter is set.
78
  * @return @c true when at least one feed is defined, @c false otherwise.
79
  */
80
+ public function has_feed($feed=null)
81
  {
82
+ if (is_null($feed)) {
83
+ foreach ($this->feed as $f) {
84
+ if ($f->is_activated())
85
+ return true;
86
+ }
87
+ return false;
88
+ }
89
+ else {
90
+ foreach ($this->feed as $f) {
91
+ if ($f->is_activated() && $f->get_name() === $feed)
92
+ return true;
93
+ }
94
+ return false;
95
+ }
96
  }
97
 
98
  /** @brief Assigns new feed name replacing any existing one.
101
  public function set_feed($feed)
102
  {
103
  $copy = $this->copy();
104
+ is_null($assignment_res = $copy->on_assignment()) ? null : $copy = $assignment_res;
105
+ $copy->feed = array(new AfsFeed($feed, true));
106
  return $copy;
107
  }
108
 
112
  public function add_feed($feed)
113
  {
114
  $copy = $this->copy();
115
+ is_null($assignment_res = $copy->on_assignment()) ? null : $copy = $assignment_res;
116
+
117
+ $feed_found = false;
118
+ foreach ($copy->feed as $f) {
119
+ if ($f->get_name() === $feed) {
120
+ $f->set_activated(true);
121
+ $feed_found = true;
122
+ break;
123
+ }
124
+ }
125
+
126
+ if (! $feed_found) {
127
+ $copy->feed[] = new AfsFeed($feed, true);
128
+ }
129
+
130
  return $copy;
131
  }
132
 
133
+ protected function get_feed($feed) {
134
+ foreach ($this->feed as $f) {
135
+ if ($f->get_name() === $feed) {
136
+ return $f;
137
+ }
138
+ }
139
+ return null;
140
+ }
141
+
142
  /** @brief Retrieves all defined feeds.
143
  * @return defined feeds in array or null when no feed is defined.
144
  */
145
  public function get_feeds()
146
  {
147
+ $feeds = array();
148
+ foreach ($this->feed as $feed) {
149
+ $feeds[] = $feed->get_name();
150
+ }
151
+ return $feeds;
152
  }
153
  /** @} */
154
 
158
  /** @brief Checks whether current instance has a query.
159
  * @return true when a query is defined, false otherwise.
160
  */
161
+ public function has_query($feed=null)
162
  {
163
+ return $this->has_parameter('query', $feed);
164
  }
165
  /** @brief Retrieves the query.
166
  *
168
  * query by calling @a has_query.
169
  * @return the query.
170
  */
171
+ public function get_query($feed=null)
172
  {
173
+ return $this->get_parameter('query', $feed);
174
  }
175
  /** @brief Assigns new query value.
176
  *
178
  * @param $new_query [in] query to assign to the instance.
179
  * @return new up to date instance.
180
  */
181
+ public function set_query($new_query, $feed=null)
182
  {
183
  $copy = $this->copy();
184
+ is_null($assignment_res = $copy->on_assignment()) ? null : $copy = $assignment_res;
185
+
186
+ $copy->set_parameter('query', $new_query, $feed);
187
+
188
  return $this->auto_set_from ? $copy->set_from(AfsOrigin::SEARCHBOX) : $copy;
189
  }
190
  /** @} */
195
  /** @brief Checks whether replies is set.
196
  * @return always true.
197
  */
198
+ public function has_replies($feed=null)
199
  {
200
+ return $this->has_parameter('replies', $feed);
201
  }
202
  /** @brief Defines new number of replies.
203
  * @param $replies_nb [in] requested number of replies. It should be
205
  * @return new up to date instance.
206
  * @exception Exception on invalid replies number provided.
207
  */
208
+ public function set_replies($replies_nb, $feed=null)
209
  {
 
 
210
  $copy = $this->copy();
211
+ is_null($assignment_res = $copy->on_assignment()) ? null : $copy = $assignment_res;
212
+
213
+ $copy->set_parameter('replies', (int) $replies_nb, $feed);
214
+
215
+ return $this->auto_set_from ? $copy->set_from(AfsOrigin::SEARCHBOX) : $copy;
216
  }
217
  /** @brief Get number of replies per page.
218
  * @return number of replies per reply page.
219
  */
220
+ public function get_replies($feed=null)
221
  {
222
+ return $this->get_parameter('replies', $feed);
223
  }
224
  /** @} */
225
 
246
  * @return current instance.
247
  * @exception Exception when provided origin value is invalid.
248
  */
249
+ public function set_from($from, $feed=null)
250
  {
251
  AfsOrigin::check_value($from, 'Invalid query origin: ');
252
+ $this->set_parameter('from', $from, $feed);
253
  return $this;
254
  }
255
  /** @brief Retrieves origin of the query.
256
  * @return origin of the query.
257
  */
258
+ public function get_from($feed=null)
259
  {
260
+ return $this->get_parameter('from', $feed);
261
  }
262
  /** @} */
263
 
274
  */
275
  public function set_user_id($user_id)
276
  {
277
+ $this->set_parameter('userId', $user_id);
278
  return $this;
279
  }
280
  /** @brief Checks whether user id is set.
290
  */
291
  public function get_user_id()
292
  {
293
+ return $this->get_parameter('userId');
294
  }
295
 
296
  /** @brief Defines session id.
300
  */
301
  public function set_session_id($session_id)
302
  {
303
+ $this->set_parameter('sessionId', $session_id);
304
  return $this;
305
  }
306
  /** @brief Checks whether session id is set.
316
  */
317
  public function get_session_id()
318
  {
319
+ return $this->get_parameter('sessionId');
320
  }
321
 
322
  /** @brief Initializes user id and session id.
378
  */
379
  public function add_log($value)
380
  {
381
+ $this->log[] = new AfsSingleValueParameter('log', $value);
382
  return $this;
383
  }
384
 
389
  */
390
  public function get_logs()
391
  {
392
+ $logs = array();
393
+ foreach ($this->log as $log) {
394
+ $logs[] = $log->get_value();
395
+ }
396
+
397
+ return $logs;
398
  }
399
  /** @} */
400
 
404
  /** @brief Checks whether key parameter is set.
405
  * @return True when key parameter is set, false otherwise.
406
  */
407
+ public function has_key($feed=null)
408
  {
409
+ return $this->has_parameter('key', $feed);
410
  }
411
  /** @brief Defines key id.
412
  * @param $key_id [in] Key id to set.
413
  * @return Current instance.
414
  */
415
+ public function set_key($key_id, $feed=null)
416
  {
417
+ $this->set_parameter('key', $key_id, $feed);
418
  return $this;
419
  }
420
  /** @brief Retrieves key value.
421
  * @return Key value.
422
  */
423
+ public function get_key($feed=null)
424
  {
425
+ return $this->get_parameter('key', $feed);
426
  }
427
  /** @} */
428
 
449
  if ($own_param != null && !empty($own_param)) {
450
  if (is_object($own_param) && is_callable(array($own_param, 'format')))
451
  $own_param = $own_param->format();
452
+ elseif (is_array($own_param)) {
453
+ $formatted_param = array();
454
+ foreach ($own_param as $key => $param_value) {
455
+ if (is_object($param_value) && is_callable(array($param_value, 'format'))) {
456
+ $formatted_value = $param_value->format();
457
+ if (is_array($formatted_value))
458
+ $formatted_param = array_merge($formatted_param, $formatted_value);
459
+ else
460
+ $formatted_param[$key] = $formatted_value;
461
+ } else {
462
+ $formatted_param[$key] = $param_value;
463
+ }
464
+ }
465
+ $own_param = $formatted_param;
466
+ }
467
  $result[$param] = $own_param;
468
  }
469
  }
470
+
471
+ $result = $this->add_feed_parameters($parameters, $result);
472
  return $result;
473
  }
474
 
475
+ private function add_feed_parameters(array $parameters_to_add, array $parameters) {
476
+
477
+ foreach($this->feed as $feed) {
478
+ if ($feed->is_activated()) {
479
+ if (! array_key_exists('feed', $parameters))
480
+ $parameters['feed'] = array();
481
+
482
+ $parameters['feed'][] = $feed->get_name();
483
+ }
484
+
485
+ $feed_parameters = $feed->get_parameters($parameters_to_add);
486
+ /* feed parameter should override default parameter
487
+ foreach ($feed_parameters as $name => $parameter) {
488
+ list($name, $feed) = explode('@', $name);
489
+ if (array_key_exists($name, $parameters) === true) {
490
+ unset($parameters[$name]);
491
+ }
492
+ }*/
493
+
494
+ $parameters = array_merge($parameters, $feed_parameters);
495
+ }
496
+
497
+ return $parameters;
498
+ }
499
+
500
  private function get_aggregated_relevant_parameters()
501
  {
502
  return array_merge(AfsQueryBase::get_relevant_parameters(), $this->get_relevant_parameters());
514
  */
515
  protected function get_relevant_parameters()
516
  {
517
+ return array_merge(array('replies', 'query'), array_keys($this->custom_parameters));
518
  }
519
 
520
  /** @brief Retrieves additional parameters.
532
  return $this->custom_parameters;
533
  }
534
 
535
+ public function set_custom_parameter($key, $value, $feed=null)
536
  {
537
  $this->custom_parameters[$key] = $value;
538
  }
543
  if(property_exists($this, $name)) {
544
  //$name is a field of AfsQueryBase
545
  return $this->$name;
546
+ } elseif (method_exists($this, $name)) {
547
+ return $this->$name;
548
  } else {
549
  if (array_key_exists($name, $this->custom_parameters)) {
550
  //$name is a custom parameter
554
  }
555
  }
556
  }
557
+
558
+
559
+ protected function has_parameter($param, $feed=null)
560
+ {
561
+ if (! is_null($feed) && ($f = $this->get_feed($feed)) !== null) {
562
+ return $f->get_parameter($param) == null ? false : true;
563
+ } else {
564
+ return $this->$param != null;
565
+ }
566
+ }
567
+
568
+ protected function get_parameter($param, $feed=null)
569
+ {
570
+ if (! is_null($feed) && ($f = $this->get_feed($feed)) != null) {
571
+ return $f->get_parameter($param)->get_value();
572
+ } else {
573
+ if (is_null($this->$param)) {
574
+ return null;
575
+ } else {
576
+ return $this->$param->get_value();
577
+ }
578
+ }
579
+ }
580
+
581
+ protected function set_parameter($param, $value, $feed=null) {
582
+ if (! is_null($feed) && ($f = $this->get_feed($feed)) !== null) {
583
+ if (($q = $f->get_parameter($param)) !== null) {
584
+ $f->get_parameter($param)->set_value($value);
585
+ } else {
586
+ $f->add_parameters(new AfsSingleValueParameter($param, $value));
587
+ }
588
+ } elseif (! is_null($feed)) {
589
+ $f = new AfsFeed($feed, false);
590
+ $f->add_parameters(new AfsSingleValueParameter($param, $value));
591
+ $this->feed[] = $f;
592
+ } else {
593
+ $this->$param = new AfsSingleValueParameter($param, $value);
594
+ }
595
+ }
596
  }
lib/antidot/AFS/afs_query_parameter.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Created by PhpStorm.
4
+ * User: ct
5
+ * Date: 2/9/15
6
+ * Time: 1:56 PM
7
+ */
8
+ abstract class AfsQueryParameter
9
+ {
10
+ protected $key;
11
+
12
+ public function __construct($key) {
13
+ $this->key = $key;
14
+ }
15
+
16
+ public function get_key() {
17
+ return $this->key;
18
+ }
19
+
20
+ public function copy() {
21
+ return clone($this);
22
+ }
23
+
24
+ public function format() {
25
+ throw new AfsNotImplementedException();
26
+ }
27
+ }
lib/antidot/AFS/afs_single_value_parameter.php ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Created by PhpStorm.
4
+ * User: ct
5
+ * Date: 2/9/15
6
+ * Time: 1:55 PM
7
+ */
8
+
9
+ require_once 'AFS/afs_query_parameter.php';
10
+
11
+ class AfsSingleValueParameter extends AfsQueryParameter
12
+ {
13
+ protected $key;
14
+ protected $value;
15
+
16
+ public function __construct($key, $value) {
17
+ parent::__construct($key);
18
+ $this->value = $value;
19
+ }
20
+
21
+ /**
22
+ * @brief set the value of current parameter
23
+ * @param $value
24
+ */
25
+ public function set_value($value) {
26
+ $this->value = $value;
27
+ }
28
+
29
+ /**
30
+ * @brief get the current value of parameter
31
+ * @return parameter value
32
+ */
33
+ public function get_value()
34
+ {
35
+ return $this->value;
36
+ }
37
+
38
+ /**
39
+ * @brief format this parameter
40
+ * @return parameter value
41
+ */
42
+ public function format() {
43
+ return $this->value;
44
+ }
45
+ }
lib/antidot/AIF/afs_document.php CHANGED
@@ -27,24 +27,24 @@ class AfsDocument
27
  *
28
  * @exception InvalidArgumentException when data is not a string.
29
  */
30
- public function __construct($data=null, $mime_type=null)
31
  {
32
- if (! is_null($data)) {
33
  $this->set_content($data, $mime_type);
34
  }
35
  }
36
-
37
- private function set_mime_compat($file)
38
- {
39
- $this->mime_type = mime_content_type($file);
40
- if ($this->mime_type === false) {
41
- $fileMetaData = stream_get_meta_data($file);
42
- $fileName = $fileMetaData['uri'];
43
- $fileInfo = `file -iL $fileName 2>/dev/null`;
44
- preg_match("/:([^;]*)/", $fileInfo, $mime);
45
- $this->mime_type = trim($mime[1]);
46
- }
47
- }
48
 
49
  private function set_mime_from_filename($filename)
50
  {
@@ -52,9 +52,9 @@ class AfsDocument
52
  $magic = new finfo(FILEINFO_MIME_TYPE);
53
  $this->mime_type = $magic->file($filename);
54
  } else {
55
- $file = fopen($filename, "r");
56
- $this->set_mime_compat($file);
57
- fclose($file);
58
  }
59
  }
60
 
@@ -67,8 +67,8 @@ class AfsDocument
67
  $temp = tmpfile();
68
  fwrite($temp, $data, 2048);
69
  fseek($temp, 0);
70
- $this->set_mime_compat($temp);
71
- fclose($temp);
72
  }
73
  }
74
 
@@ -80,10 +80,10 @@ class AfsDocument
80
  *
81
  * @exception InvalidArgumentException when data is not a string.
82
  */
83
- public function set_content($data, $mime_type=null)
84
  {
85
  $this->clean_up();
86
- if (! is_string($data)) {
87
  throw new InvalidArgumentException('Provided data is not of string type: '
88
  . gettype($data));
89
  }
@@ -103,10 +103,10 @@ class AfsDocument
103
  *
104
  * @exception RuntimeException when provided @a filename does not exist.
105
  */
106
- public function set_content_from_file($filename, $mime_type=null)
107
  {
108
  $this->clean_up();
109
- if (! file_exists($filename)) {
110
  throw new RuntimeException('Cannot define document using '
111
  . 'unexisting file: ' . $filename);
112
  }
@@ -123,7 +123,7 @@ class AfsDocument
123
  */
124
  public function is_valid()
125
  {
126
- return ! is_null($this->data) || ! is_null($this->filename);
127
  }
128
 
129
  /** @brief Retrieve document filename.
@@ -165,7 +165,7 @@ class AfsDocument
165
  {
166
  $this->data = null;
167
  $this->filename = null;
168
- if (! is_null($this->temp_file)) {
169
  fclose($this->temp_file);
170
  $this->temp_file = null;
171
  }
27
  *
28
  * @exception InvalidArgumentException when data is not a string.
29
  */
30
+ public function __construct($data = null, $mime_type = null)
31
  {
32
+ if (!is_null($data)) {
33
  $this->set_content($data, $mime_type);
34
  }
35
  }
36
+
37
+ private function set_mime_compat($file)
38
+ {
39
+ $this->mime_type = mime_content_type($file);
40
+ if ($this->mime_type === false) {
41
+ $fileMetaData = stream_get_meta_data($file);
42
+ $fileName = $fileMetaData['uri'];
43
+ $fileInfo = `file -iL $fileName 2>/dev/null`;
44
+ preg_match("/:([^;]*)/", $fileInfo, $mime);
45
+ $this->mime_type = trim($mime[1]);
46
+ }
47
+ }
48
 
49
  private function set_mime_from_filename($filename)
50
  {
52
  $magic = new finfo(FILEINFO_MIME_TYPE);
53
  $this->mime_type = $magic->file($filename);
54
  } else {
55
+ $file = fopen($filename, "r");
56
+ $this->set_mime_compat($file);
57
+ fclose($file);
58
  }
59
  }
60
 
67
  $temp = tmpfile();
68
  fwrite($temp, $data, 2048);
69
  fseek($temp, 0);
70
+ $this->set_mime_compat($temp);
71
+ fclose($temp);
72
  }
73
  }
74
 
80
  *
81
  * @exception InvalidArgumentException when data is not a string.
82
  */
83
+ public function set_content($data, $mime_type = null)
84
  {
85
  $this->clean_up();
86
+ if (!is_string($data)) {
87
  throw new InvalidArgumentException('Provided data is not of string type: '
88
  . gettype($data));
89
  }
103
  *
104
  * @exception RuntimeException when provided @a filename does not exist.
105
  */
106
+ public function set_content_from_file($filename, $mime_type = null)
107
  {
108
  $this->clean_up();
109
+ if (!file_exists($filename)) {
110
  throw new RuntimeException('Cannot define document using '
111
  . 'unexisting file: ' . $filename);
112
  }
123
  */
124
  public function is_valid()
125
  {
126
+ return !is_null($this->data) || !is_null($this->filename);
127
  }
128
 
129
  /** @brief Retrieve document filename.
165
  {
166
  $this->data = null;
167
  $this->filename = null;
168
+ if (!is_null($this->temp_file)) {
169
  fclose($this->temp_file);
170
  $this->temp_file = null;
171
  }
lib/antidot/COMMON/afs_exception.php CHANGED
@@ -2,9 +2,19 @@
2
 
3
  /** @brief Base class for AFS exceptions. */
4
  abstract class AfsBaseException extends Exception
5
- { }
 
6
 
7
 
8
  /** @brief Not implemented exception. */
9
  class AfsNotImplementedException extends AfsBaseException
10
  { }
 
 
 
 
 
 
 
 
 
2
 
3
  /** @brief Base class for AFS exceptions. */
4
  abstract class AfsBaseException extends Exception
5
+ {
6
+ }
7
 
8
 
9
  /** @brief Not implemented exception. */
10
  class AfsNotImplementedException extends AfsBaseException
11
  { }
12
+
13
+ /**
14
+ * @brief Unknow promote type
15
+ */
16
+ class AfsUnknowPromoteTypeException extends AfsBaseException {
17
+ public function __construct($message) {
18
+ parent::__construct('Unknow promote type: ' . $message);
19
+ }
20
+ }
lib/antidot/COMMON/afs_versions.php CHANGED
@@ -1,4 +1,4 @@
1
  <?php
2
 
3
 
4
- define('AFS_VERSION_76', '7.6');
1
  <?php
2
 
3
 
4
+ define('AFS_VERSION_77', '7.7');
lib/antidot/COMMON/lib/JsonPath/JsonPath.php ADDED
@@ -0,0 +1,279 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Peekmo\JsonPath;
4
+
5
+
6
+ /* JSONPath 0.8.3 - XPath for JSON
7
+ *
8
+ * Copyright (c) 2007 Stefan Goessner (goessner.net)
9
+ * Licensed under the MIT (MIT-LICENSE.txt) licence.
10
+ *
11
+ * Modified by Axel Anceau
12
+ */
13
+
14
+
15
+ class JsonPath
16
+ {
17
+ private $obj = null;
18
+ private $resultType = "Value";
19
+ private $result = array();
20
+ private $subx = array();
21
+ private $keywords = array('=', ')', '!', '<', '>');
22
+
23
+ public function jsonPath($obj, $expr, $args = null)
24
+ {
25
+ if (is_object($obj)) {
26
+ throw new \Exception('You sent an object, not an array.');
27
+ }
28
+
29
+ $this->resultType = ($args ? $args['resultType'] : "VALUE");
30
+ $x = $this->normalize($expr);
31
+
32
+ $this->obj = $obj;
33
+ if ($expr && $obj && ($this->resultType == "VALUE" || $this->resultType == "PATH")) {
34
+ $this->trace(preg_replace("/^\\$;/", "", $x), $obj, "$");
35
+ if (count($this->result)) {
36
+ return $this->result;
37
+ }
38
+
39
+ return false;
40
+ }
41
+ }
42
+
43
+ // normalize path expression
44
+ private function normalize($expression)
45
+ {
46
+ // Replaces filters by #0 #1...
47
+ $expression = preg_replace_callback(
48
+ array("/[\['](\??\(.*?\))[\]']/", "/\['(.*?)'\]/"),
49
+ array(&$this, "tempFilters"),
50
+ $expression
51
+ );
52
+
53
+ // ; separator between each elements
54
+ $expression = preg_replace(
55
+ array("/'?\.'?|\['?/", "/;;;|;;/", "/;$|'?\]|'$/"),
56
+ array(";", ";..;", ""),
57
+ $expression
58
+ );
59
+
60
+ // Restore filters
61
+ $expression = preg_replace_callback("/#([0-9]+)/", array(&$this, "restoreFilters"), $expression);
62
+ $this->result = array(); // result array was temporarily used as a buffer ..
63
+ return $expression;
64
+ }
65
+
66
+ /**
67
+ * Pushs the filter into the list
68
+ * @param string $filter
69
+ * @return string
70
+ */
71
+ private function tempFilters($filter)
72
+ {
73
+ $f = $filter[1];
74
+ $elements = explode('\'', $f);
75
+
76
+ // Hack to make "dot" works on filters
77
+ for ($i=0, $m=0; $i<count($elements); $i++) {
78
+ if ($m%2 == 0) {
79
+ if ($i > 0 && substr($elements[$i-1], 0, 1) == '\\') {
80
+ continue;
81
+ }
82
+
83
+ $e = explode('.', $elements[$i]);
84
+ $str = ''; $first = true;
85
+ foreach ($e as $substr) {
86
+ if ($first) {
87
+ $str = $substr;
88
+ $first = false;
89
+ continue;
90
+ }
91
+
92
+ $end = null;
93
+ if (false !== $pos = $this->strpos_array($substr, $this->keywords)) {
94
+ list($substr, $end) = array(substr($substr, 0, $pos), substr($substr, $pos, strlen($substr)));
95
+ }
96
+
97
+ $str .= '[' . $substr . ']';
98
+ if (null !== $end) {
99
+ $str .= $end;
100
+ }
101
+ }
102
+ $elements[$i] = $str;
103
+ }
104
+
105
+ $m++;
106
+ }
107
+
108
+ return "[#" . (array_push($this->result, implode('\'', $elements)) - 1) . "]";
109
+ }
110
+
111
+ /**
112
+ * Get a filter back
113
+ * @param string $filter
114
+ * @return mixed
115
+ */
116
+ private function restoreFilters($filter)
117
+ {
118
+ return $this->result[$filter[1]];
119
+ }
120
+
121
+ /**
122
+ * Builds json path expression
123
+ * @param string $path
124
+ * @return string
125
+ */
126
+ private function asPath($path)
127
+ {
128
+ $expr = explode(";", $path);
129
+ $fullPath = "$";
130
+ for ($i = 1, $n = count($expr); $i < $n; $i++) {
131
+ $fullPath .= preg_match("/^[0-9*]+$/", $expr[$i]) ? ("[" . $expr[$i] . "]") : ("['" . $expr[$i] . "']");
132
+ }
133
+
134
+ return $fullPath;
135
+ }
136
+
137
+ private function store($p, $v)
138
+ {
139
+ if ($p) {
140
+ array_push($this->result, ($this->resultType == "PATH" ? $this->asPath($p) : $v));
141
+ }
142
+
143
+ return !!$p;
144
+ }
145
+
146
+ private function trace($expr, $val, $path)
147
+ {
148
+ if ($expr !== "" && $expr !== "$") {
149
+ $x = explode(";", $expr);
150
+ $loc = array_shift($x);
151
+ $x = implode(";", $x);
152
+
153
+ if (is_array($val) && array_key_exists($loc, $val)) {
154
+ $this->trace($x, $val[$loc], $path . ";" . $loc);
155
+ }
156
+ else if ($loc == "*") {
157
+ $this->walk($loc, $x, $val, $path, array(&$this, "_callback_03"));
158
+ }
159
+ else if ($loc === "..") {
160
+ $this->trace($x, $val, $path);
161
+ $this->walk($loc, $x, $val, $path, array(&$this, "_callback_04"));
162
+ }
163
+ else if (preg_match("/^\(.*?\)$/", $loc)) { // [(expr)]
164
+ $this->trace($this->evalx($loc, $val, substr($path, strrpos($path, ";") + 1)) . ";" . $x, $val, $path);
165
+ }
166
+ else if (preg_match("/^\?\(.*?\)$/", $loc)) { // [?(expr)]
167
+ $this->walk($loc, $x, $val, $path, array(&$this, "_callback_05"));
168
+ }
169
+ else if (preg_match("/^(-?[0-9]*):(-?[0-9]*):?(-?[0-9]*)$/", $loc)) { // [start:end:step] phyton slice syntax
170
+ $this->slice($loc, $x, $val, $path);
171
+ }
172
+ else if (preg_match("/,/", $loc)) { // [name1,name2,...]
173
+ for ($s = preg_split("/'?,'?/", $loc), $i = 0, $n = count($s); $i < $n; $i++)
174
+ $this->trace($s[$i] . ";" . $x, $val, $path);
175
+ }
176
+ } else {
177
+ $this->store($path, $val);
178
+ }
179
+ }
180
+
181
+ private function _callback_03($m, $l, $x, $v, $p)
182
+ {
183
+ $this->trace($m . ";" . $x, $v, $p);
184
+ }
185
+
186
+
187
+ private function _callback_04($m, $l, $x, $v, $p)
188
+ {
189
+ if (is_array($v[$m])) {
190
+ $this->trace("..;" . $x, $v[$m], $p . ";" . $m);
191
+ }
192
+ }
193
+
194
+ private function _callback_05($m, $l, $x, $v, $p)
195
+ {
196
+ if ($this->evalx(preg_replace("/^\?\((.*?)\)$/", "$1", $l), $v[$m])) {
197
+ $this->trace($m . ";" . $x, $v, $p);
198
+ }
199
+ }
200
+
201
+ private function walk($loc, $expr, $val, $path, $f)
202
+ {
203
+ foreach ($val as $m => $v) {
204
+ call_user_func($f, $m, $loc, $expr, $val, $path);
205
+ }
206
+ }
207
+
208
+ private function slice($loc, $expr, $v, $path)
209
+ {
210
+ $s = explode(":", preg_replace("/^(-?[0-9]*):(-?[0-9]*):?(-?[0-9]*)$/", "$1:$2:$3", $loc));
211
+ $len = count($v);
212
+ $start = (int)$s[0] ? $s[0] : 0;
213
+ $end = (int)$s[1] ? $s[1] : $len;
214
+ $step = (int)$s[2] ? $s[2] : 1;
215
+ $start = ($start < 0) ? max(0, $start + $len) : min($len, $start);
216
+ $end = ($end < 0) ? max(0, $end + $len) : min($len, $end);
217
+ for ($i = $start; $i < $end; $i += $step) {
218
+ $this->trace($i . ";" . $expr, $v, $path);
219
+ }
220
+ }
221
+
222
+ /**
223
+ * @param string $x filter
224
+ * @param array $v node
225
+ *
226
+ * @param string $vname
227
+ * @return string
228
+ */
229
+ private function evalx($x, $v, $vname = null)
230
+ {
231
+ $name = "";
232
+ $expr = preg_replace(array("/\\$/", "/@/"), array("\$this->obj", "\$v"), $x);
233
+ $res = eval("\$name = $expr;");
234
+
235
+ if ($res === false) {
236
+ print("(jsonPath) SyntaxError: " . $expr);
237
+ } else {
238
+ return $name;
239
+ }
240
+ }
241
+
242
+ private function toObject($array)
243
+ {
244
+ //$o = (object)'';
245
+ $o = new \stdClass();
246
+
247
+ foreach ($array as $key => $value) {
248
+ if (is_array($value)) {
249
+ $value = $this->toObject($value);
250
+ }
251
+
252
+ $o->$key = $value;
253
+ }
254
+
255
+ return $o;
256
+ }
257
+
258
+ /**
259
+ * Search one of the given needs in the array
260
+ * @param string $haystack
261
+ * @param array $needles
262
+ * @return bool|string
263
+ */
264
+ private function strpos_array($haystack, array $needles)
265
+ {
266
+ $closer = 10000;
267
+ foreach($needles as $needle) {
268
+ if (false !== $pos = strpos($haystack, $needle)) {
269
+ if ($pos < $closer) {
270
+ $closer = $pos;
271
+ }
272
+ }
273
+ }
274
+
275
+ return 10000 === $closer ? false : $closer;
276
+ }
277
+ }
278
+
279
+ ?>
lib/antidot/COMMON/lib/JsonPath/JsonStore.php ADDED
@@ -0,0 +1,223 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Peekmo\JsonPath;
4
+
5
+ /* JSONStore 0.5 - JSON structure as storage
6
+ *
7
+ * Copyright (c) 2007 Stefan Goessner (goessner.net)
8
+ * Licensed under the MIT (MIT-LICENSE.txt) licence.
9
+ *
10
+ * Modified by Axel Anceau
11
+ */
12
+
13
+ class JsonStore
14
+ {
15
+ private static $emptyArray = array();
16
+
17
+ /**
18
+ * @var array
19
+ */
20
+ private $data;
21
+
22
+ /**
23
+ * @var JsonPath
24
+ */
25
+ private $jsonPath;
26
+
27
+ /**
28
+ * @param string|array|\stdClass $data
29
+ */
30
+ public function __construct($data)
31
+ {
32
+ $this->jsonPath = new JsonPath();
33
+ $this->setData($data);
34
+ }
35
+
36
+ /**
37
+ * Sets JsonStore's manipulated data
38
+ * @param string|array|\stdClass $data
39
+ */
40
+ public function setData($data)
41
+ {
42
+ $this->data = $data;
43
+
44
+ if (is_string($this->data)) {
45
+ $this->data = json_decode($this->data, true);
46
+ } else if (is_object($data)) {
47
+ $this->data = json_decode(json_encode($this->data), true);
48
+ } else if (!is_array($data)) {
49
+ throw new \InvalidArgumentException(sprintf('Invalid data type in JsonStore. Expected object, array or string, got %s', gettype($data)));
50
+ }
51
+ }
52
+
53
+ /**
54
+ * JsonEncoded version of the object
55
+ * @return string
56
+ */
57
+ public function toString()
58
+ {
59
+ return json_encode($this->data);
60
+ }
61
+
62
+ /**
63
+ * Returns the given json string to object
64
+ * @return \stdClass
65
+ */
66
+ public function toObject()
67
+ {
68
+ return json_decode(json_encode($this->data));
69
+ }
70
+
71
+ /**
72
+ * Returns the given json string to array
73
+ * @return array
74
+ */
75
+ public function toArray()
76
+ {
77
+ return $this->data;
78
+ }
79
+
80
+ /**
81
+ * Gets elements matching the given JsonPath expression
82
+ * @param string $expr JsonPath expression
83
+ * @param bool $unique Gets unique results or not
84
+ * @return array
85
+ */
86
+ public function get($expr, $unique = false)
87
+ {
88
+ if ((($exprs = $this->normalizedFirst($expr)) !== false) &&
89
+ (is_array($exprs) || $exprs instanceof \Traversable)
90
+ ) {
91
+ $values = array();
92
+
93
+ foreach ($exprs as $expr) {
94
+ $o =& $this->data;
95
+ $keys = preg_split(
96
+ "/([\"'])?\]\[([\"'])?/",
97
+ preg_replace(array("/^\\$\[[\"']?/", "/[\"']?\]$/"), "", $expr)
98
+ );
99
+
100
+ for ($i = 0; $i < count($keys); $i++) {
101
+ $o =& $o[$keys[$i]];
102
+ }
103
+
104
+ $values[] = & $o;
105
+ }
106
+
107
+ if (true === $unique) {
108
+ if (!empty($values) && is_array($values[0])) {
109
+ array_walk($values, function(&$value) {
110
+ $value = json_encode($value);
111
+ });
112
+
113
+ $values = array_unique($values);
114
+ array_walk($values, function(&$value) {
115
+ $value = json_decode($value, true);
116
+ });
117
+
118
+ return array_values($values);
119
+ }
120
+
121
+ return array_unique($values);
122
+ }
123
+
124
+ return $values;
125
+ }
126
+
127
+ return self::$emptyArray;
128
+ }
129
+
130
+ /**
131
+ * Sets the value for all elements matching the given JsonPath expression
132
+ * @param string $expr JsonPath expression
133
+ * @param mixed $value Value to set
134
+ * @return bool returns true if success
135
+ */
136
+ function set($expr, $value)
137
+ {
138
+ if ($res =& $this->get($expr)) {
139
+ foreach ($res as &$r) {
140
+ $r = $value;
141
+ }
142
+
143
+ return true;
144
+ }
145
+
146
+ return false;
147
+ }
148
+
149
+ /**
150
+ * Adds one or more elements matching the given json path expression
151
+ * @param string $parentexpr JsonPath expression to the parent
152
+ * @param mixed $value Value to add
153
+ * @param string $name Key name
154
+ * @return bool returns true if success
155
+ */
156
+ public function add($parentexpr, $value, $name = "")
157
+ {
158
+ if ($parents =& $this->get($parentexpr)) {
159
+
160
+ foreach ($parents as &$parent) {
161
+ $parent = is_array($parent) ? $parent : array();
162
+
163
+ if ($name != "") {
164
+ $parent[$name] = $value;
165
+ } else {
166
+ $parent[] = $value;
167
+ }
168
+ }
169
+
170
+ return true;
171
+ }
172
+
173
+ return false;
174
+ }
175
+
176
+ /**
177
+ * Removes all elements matching the given jsonpath expression
178
+ * @param string $expr JsonPath expression
179
+ * @return bool returns true if success
180
+ */
181
+ public function remove($expr)
182
+ {
183
+ if ((($exprs = $this->normalizedFirst($expr)) !== false) &&
184
+ (is_array($exprs) || $exprs instanceof \Traversable)
185
+ ) {
186
+ foreach ($exprs as &$expr) {
187
+ $o =& $this->data;
188
+ $keys = preg_split(
189
+ "/([\"'])?\]\[([\"'])?/",
190
+ preg_replace(array("/^\\$\[[\"']?/", "/[\"']?\]$/"), "", $expr)
191
+ );
192
+ for ($i = 0; $i < count($keys) - 1; $i++) {
193
+ $o =& $o[$keys[$i]];
194
+ }
195
+
196
+ unset($o[$keys[$i]]);
197
+ }
198
+
199
+ return true;
200
+ }
201
+
202
+ return false;
203
+ }
204
+
205
+ private function normalizedFirst($expr)
206
+ {
207
+ if ($expr == "") {
208
+ return false;
209
+ } else {
210
+ if (preg_match("/^\$(\[([0-9*]+|'[-a-zA-Z0-9_ ]+')\])*$/", $expr)) {
211
+ print("normalized: " . $expr);
212
+
213
+ return $expr;
214
+ } else {
215
+ $res = $this->jsonPath->jsonPath($this->data, $expr, array("resultType" => "PATH"));
216
+
217
+ return $res;
218
+ }
219
+ }
220
+ }
221
+ }
222
+
223
+ ?>
lib/antidot/COMMON/php-SAI/.gitignore CHANGED
@@ -1,11 +1,11 @@
1
-
2
- /.idea/.name
3
- /.idea/codeStyleSettings.xml
4
- /.idea/encodings.xml
5
- /.idea/misc.xml
6
- /.idea/modules.xml
7
- /.idea/php-SAI.iml
8
- /.idea/scopes/scope_settings.xml
9
- /.idea/vcs.xml
10
- /.idea/workspace.xml
11
  /.idea/php.xml
1
+
2
+ /.idea/.name
3
+ /.idea/codeStyleSettings.xml
4
+ /.idea/encodings.xml
5
+ /.idea/misc.xml
6
+ /.idea/modules.xml
7
+ /.idea/php-SAI.iml
8
+ /.idea/scopes/scope_settings.xml
9
+ /.idea/vcs.xml
10
+ /.idea/workspace.xml
11
  /.idea/php.xml
lib/antidot/README.md CHANGED
@@ -17,6 +17,12 @@ Documentation
17
  http://antidot.github.io/PHP_API/doc/html/index.html
18
 
19
 
 
 
 
 
 
 
20
  FAQ
21
  ---
22
 
17
  http://antidot.github.io/PHP_API/doc/html/index.html
18
 
19
 
20
+ Tests
21
+ ------
22
+
23
+ [![Build Status](https://travis-ci.org/antidot/PHP_API.png?branch=master)](https://travis-ci.org/antidot/PHP_API)
24
+
25
+
26
  FAQ
27
  ---
28
 
lib/antidot/afs_lib.doxygen CHANGED
@@ -1,3 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  # Doxyfile 1.8.5
2
 
3
  # This file describes the settings to be used by the documentation system
@@ -38,7 +53,7 @@ PROJECT_NAME = "Antidot PHP API"
38
  # could be handy for archiving the generated documentation or if some version
39
  # control system is used.
40
 
41
- PROJECT_NUMBER = "version 0.12.1"
42
 
43
  # Using the PROJECT_BRIEF tag one can provide an optional one line description
44
  # for a project that appears at the top of each page and should give viewer a
@@ -2308,3 +2323,6 @@ GENERATE_LEGEND = YES
2308
  # This tag requires that the tag HAVE_DOT is set to YES.
2309
 
2310
  DOT_CLEANUP = YES
 
 
 
1
+ Skip to content
2
+ This repository
3
+ Explore
4
+ Gist
5
+ Blog
6
+ Help
7
+ charlthibault charlthibault
8
+
9
+ 9 Unwatch
10
+ Star 6
11
+ Fork 5antidot/PHP_API
12
+ tag: v0.16.0 PHP_API/afs_lib.doxygen
13
+ ml on Apr 4, 2014 Add support for number of facet value replies
14
+ 0 contributors
15
+ 2311 lines (1783 sloc) 100.656 kb RawBlameHistory
16
  # Doxyfile 1.8.5
17
 
18
  # This file describes the settings to be used by the documentation system
53
  # could be handy for archiving the generated documentation or if some version
54
  # control system is used.
55
 
56
+ PROJECT_NUMBER = "version 0.16.0"
57
 
58
  # Using the PROJECT_BRIEF tag one can provide an optional one line description
59
  # for a project that appears at the top of each page and should give viewer a
2323
  # This tag requires that the tag HAVE_DOT is set to YES.
2324
 
2325
  DOT_CLEANUP = YES
2326
+ Status API Training Shop Blog About
2327
+ © 2015 GitHub, Inc. Terms Privacy Security Contact
2328
+
lib/antidot/afs_lib.php CHANGED
@@ -15,3 +15,4 @@ require_once 'AFS/SEARCH/afs_search.php';
15
  require_once 'AFS/SEARCH/FILTER/afs_filter.php';
16
 
17
  require_once 'AFS/ACP/afs_acp.php';
 
15
  require_once 'AFS/SEARCH/FILTER/afs_filter.php';
16
 
17
  require_once 'AFS/ACP/afs_acp.php';
18
+
lib/antidot/afs_version.php CHANGED
@@ -11,11 +11,11 @@ define('AFS_API_VERSION_MAJOR', 0);
11
  /** @brief API minor version number.
12
  *
13
  * You should increase this number for new small features, code improvements. */
14
- define('AFS_API_VERSION_MINOR', 13);
15
  /** @brief API fix version number.
16
  *
17
  * You should increase this number as soon as a bug is fixed.*/
18
- define('AFS_API_VERSION_FIX', 1);
19
 
20
  /** @brief API full version number. */
21
  define('AFS_API_VERSION', implode('.', array(AFS_API_VERSION_MAJOR, AFS_API_VERSION_MINOR, AFS_API_VERSION_FIX)));
11
  /** @brief API minor version number.
12
  *
13
  * You should increase this number for new small features, code improvements. */
14
+ define('AFS_API_VERSION_MINOR', 16);
15
  /** @brief API fix version number.
16
  *
17
  * You should increase this number as soon as a bug is fixed.*/
18
+ define('AFS_API_VERSION_FIX', 3);
19
 
20
  /** @brief API full version number. */
21
  define('AFS_API_VERSION', implode('.', array(AFS_API_VERSION_MAJOR, AFS_API_VERSION_MINOR, AFS_API_VERSION_FIX)));
lib/antidot/composer.json ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "antidot/php_api",
3
+ "description": "This API allows you to simplify integration of Antidot products.",
4
+ "license" : "LGPL",
5
+ "require": {
6
+ "php": ">=5.3.0"
7
+ }
8
+ }
lib/antidot/doc/data/raw_example.php CHANGED
@@ -2,29 +2,23 @@
2
  /** @file raw_example.php
3
  * @example raw_example.php
4
  */
5
-
6
  require_once "PHP_API/afs_lib.php";
7
-
8
  $search = new AfsSearch('eval.partners.antidot.net', 48000);
9
-
10
  $query = $search->build_query_from_url_parameters();
11
  $query = $query->set_lang('fr'); // language is set manually in order to get spellcheck results
12
  $query = $query->set_multi_selection_facets('classification');
13
  $query = $query->set_mono_selection_facets('afs:lang', 'has_variants', 'has_image');
14
  $query = $query->set_facet_order('price_eur', 'marketing', 'classification', 'has_variants', 'has_image');
15
  $query = $query->set_facets_values_sort_order(AfsFacetValuesSortMode::ITEMS, AfsSortOrder::DESC);
16
-
17
  $helper = $search->execute($query);
18
  $generated_url = $search->get_generated_url();
19
-
20
  $clustering_is_active = $query->has_cluster();
21
  $nsmap = array('ns' => 'http://ref.antidot.net/store/afs#');
22
-
23
  ?>
24
 
25
 
26
  <html>
27
- <head>
28
  <title>Antidot PHP API - Raw example</title>
29
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
30
  <meta charset="UTF-8">
@@ -32,32 +26,32 @@ $nsmap = array('ns' => 'http://ref.antidot.net/store/afs#');
32
  <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-theme.min.css">
33
  <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
34
  <!--[if lt IE 9]>
35
- <script src="../../assets/js/html5shiv.js"></script>
36
- <script src="../../assets/js/respond.min.js"></script>
37
  <![endif]-->
38
- </head>
39
- <body>
40
- <div>
41
  <a href="<?php echo $generated_url; ?>" target="_blank"><?php echo $generated_url; ?></a>
42
- </div>
43
- <div class="page-header">
44
- <h1>Raw example <small>based on the Antidot PHP API</small></h1>
45
- </div>
46
- <!-- ####################### Search box ########################### -->
47
- <div class="row">
48
- <div class="col-md-5"></div>
49
- <div class="input-group col-md-2">
50
  <form method="get" action="" role="form" class="input-group">
51
- <span class="input-group-addon">Search</span>
52
- <input type="search" name="query" class="form-control" placeholder="Keywords" />
53
  <span class="input-group-btn">
54
  <button class="btn btn-primary" type="submit"><span class="glyphicon glyphicon-search"></span></button>
55
  </span>
56
  </form>
57
- </div>
58
  </div>
 
59
 
60
- <!-- ####################### Current filter parameters ########################### -->
61
  <?php
62
  $params = $query->get_parameters(false);
63
  if (array_key_exists('filter', $params) && is_array($params['filter'])) {
@@ -79,7 +73,7 @@ if (array_key_exists('filter', $params) && is_array($params['filter'])) {
79
  </div>';
80
  } ?>
81
 
82
- <!-- ####################### Promote ########################### -->
83
  <?php
84
  if ($helper->has_promote()) {
85
  echo '
@@ -112,95 +106,94 @@ if ($helper->has_promote()) {
112
  // checks whether there is at least one replyset
113
  if ($helper->has_replyset()) {
114
  $replyset = $helper->get_replyset(); // Retrieves only first replyset
115
-
116
  if ($replyset->has_facet()) {
117
- /* if (in_array('facets', $replyset)) */
118
- ?>
119
- <div class="row">
120
- <div class="col-md-3">
121
- <h2>Filters</h2>
122
- <!-- ####################### Filters ########################### -->
123
- <?php
124
- foreach ($replyset->get_facets() as $facet) {
125
- /* foreach ($replyset->facets->facet as $facet) */
126
- ?>
127
- <div class="panel panel-default">
128
- <div class="panel-heading"><?php echo $facet->get_label() ?></div> <!-- $facet->labels[0]->label -->
129
- <div class="panel-body">
130
- <div class="list-group">
131
- <div class="list-group">
132
- <?php
133
- foreach ($facet->get_elements() as $value) {
134
- /* $item = null;
135
- * if ($facet->{'afs:t'} == 'FacetTree') {
136
- * $item = 'node';
137
- * } elif ($facet->{'afs:t'} == 'FacetInterval') {
138
- * $item = 'interval;
139
- * } else {
140
- * throw new Exception('Unknown facet layout: ' . $facet->{'afs:t'});
141
- * }
142
- * foreach ($facet->$item as $value) */
143
- ?>
144
- <a class="list-group-item <?php echo ($value->active ? 'active' : '') ?>" href="<?php echo $value->link ?>"><?php echo $value->label ?><span class="badge"><?php echo $value->count ?></span></a>
145
- <!-- $active = $query->has_filter($facet->id, $value->key);
146
- ...
147
- -->
148
- <?php } ?>
149
- </div>
 
 
150
  </div>
151
- </div>
152
- </div>
153
- <?php } ?>
154
- </div>
155
- <?php } ?>
156
 
157
- <div class="col-md-9">
158
- <div class="row page-header">
159
- <div class="col-md-1"></div>
160
- <div class="col-md-2">
161
- <h2>Results <span class="label label-success"><?php echo $replyset->get_meta()->get_total_replies() ?></span></h2>
162
- <h4><span class="label label-info">Duration <?php echo $replyset->get_meta()->get_duration() ?> ms</span></h4>
163
- </div>
164
- <div class="col-md-1"></div>
165
- <div class="col-md-2">
166
- <!-- ####################### Relevance ########################### -->
167
- <?php
168
- if ($query->has_sort(AfsSortBuiltins::RELEVANCE)) {
169
- if ($query->get_sort_order(AfsSortBuiltins::RELEVANCE) == AfsSortOrder::ASC) {
170
- $relevance_icon = 'glyphicon-arrow-up';
171
- $relevance_query = $query->add_sort(AfsSortBuiltins::RELEVANCE, AfsSortOrder::DESC);
172
- } else {
173
- $relevance_icon = 'glyphicon-arrow-down';
174
- $relevance_query = $query->add_sort(AfsSortBuiltins::RELEVANCE, AfsSortOrder::ASC);
175
- }
176
- } else {
177
- $relevance_query = $query->add_sort(AfsSortBuiltins::RELEVANCE, AfsSortOrder::ASC);
178
- $relevance_icon = 'glyphicon-arrow-down';
179
- }
180
- $relevance_link = $search->get_helpers_configuration()->get_query_coder()->generate_link($relevance_query);
181
- ?>
182
- <a href="<?php echo $relevance_link ?>" class="btn btn-default btn-lg active" role="button"><span class="glyphicon <?php echo $relevance_icon; ?>"></span> Relevance</a>
183
- </div>
184
- <div class="col-md-2">
185
- <?php
186
- $query_coder = $search->get_helpers_configuration()->get_query_coder();
187
- if ($clustering_is_active) {
188
- $cluster_query = $query->unset_cluster();
189
- $cluster_link = $query_coder->generate_link($query->unset_cluster());
190
- $cluster_label = 'Remove clusters';
191
- } else {
192
- $cluster_link = $query_coder->generate_link($query->set_cluster('marketing', 1)->set_overspill());
193
- $cluster_label = 'Create cluster on "marketing" filter';
194
- } ?>
195
- <a href="<?php echo $cluster_link ?>" class="btn btn-default btn-lg active" role="button"><?php echo $cluster_label ?></a>
196
- </div>
197
- </div>
198
 
199
- <!-- ####################### Clusters ########################### -->
200
- <?php
201
- if ($clustering_is_active) {
202
- foreach ($replyset->get_clusters() as $cluster) {
203
- echo '
204
  <div class="row">
205
  <div class="col-md-1"></div>
206
  <div class="col-md-5">
@@ -212,8 +205,8 @@ if ($clustering_is_active) {
212
  </div>
213
  </div>
214
  <ul class="list-unstyled">';
215
- foreach ($cluster->get_replies() as $reply) {
216
- echo '
217
  <li>
218
  <h3>' . $reply->get_title() . '</h3>
219
  <p><a href="' . $reply->get_uri() . '">' . $reply->get_uri() . '</a></p>
@@ -225,141 +218,139 @@ if ($clustering_is_active) {
225
  <li>Prices:
226
  <ul>';
227
  // Here multiple values are retrieved from client data
228
- foreach ($reply->get_clientdata()->get_values('/ns:product/ns:prices/ns:price', $nsmap) as $value)
229
- echo '<li>' . $value . '</li>';
230
- echo '
231
  </ul>
232
  </li>
233
  </ul>
234
  </p>
235
  </li>';
236
- }
237
- echo '
238
  </ul>';
239
- }
240
-
241
- echo '
242
  <div class="row">
243
  <div class="col-md-1"></div>
244
  <div class="col-md-5">
245
  <h3><span class="label label-success">Other results</span></h3>
246
  </div>
247
  </div>';
248
- } ?>
249
 
250
- <!-- ####################### Replies ########################### -->
251
- <?php
252
- echo '
253
  <ul class="list-unstyled">';
254
- foreach ($replyset->get_replies() as $reply) {
255
- ?>
256
- <li>
257
- <h3><?php echo $reply->get_title() ?></h3>
258
- <p><a href="<?php echo $reply->get_uri() ?>"><?php echo $reply->get_uri() ?></a></p>
259
- <p><?php echo $reply->get_abstract() ?></p>
260
- <p>Some client data:
261
  <ul>
262
- <li>Name: <?php echo $reply->get_clientdata()->get_value('/ns:product/ns:name', $nsmap) ?></li>
263
- <li>Availability: <?php echo $reply->get_clientdata()->get_value('/ns:product/ns:is_available', $nsmap) ?></li>
264
- <li>Prices:
265
- <ul>
266
- <?php
267
- // Here multiple values are retrieved from client data
268
- foreach ($reply->get_clientdata()->get_values('/ns:product/ns:prices/ns:price', $nsmap) as $value) {
269
- echo '<li>' . $value . '</li>';
270
- } ?>
271
- </ul>
272
- </li>
273
  </ul>
274
- </p>
275
- </li>
276
- <?php } ?>
277
- </ul>
278
- </div>
279
  </div>
280
 
281
  <!-- ####################### Pager ########################### -->
282
- <?php
283
- if ($replyset->has_pager()) {
284
- $pager = $replyset->get_pager();
285
- ?>
286
- <div class="row">
287
- <div class="row">
288
- <div class="col-md-5"></div>
289
- <div class="input-group col-md-3">
290
- <ul class="pagination">
291
- <?php
292
- foreach ($pager->get_all_pages() as $page => $url) {
293
- if ($page == $pager->get_current_no()) {
294
- $active = 'active';
295
- } else {
296
- $active = '';
297
- }
298
- ?>
299
- <li class="<?php echo $active ?>"><a href="<?php echo $url ?>"><?php echo $page ?></a></li>
300
- <?php } ?>
301
 
302
- </ul>
 
303
  </div>
304
- </div>
305
- <?php } ?>
306
 
307
  </div>
308
 
309
  <!-- ####################### Spellcheck ########################### -->
310
  <?php } elseif ($helper->has_spellcheck()) { // if no replyset, let's check spellcheck ?>
311
  <div class="row">
312
- <div class="col-md-9">
313
- <div class="row">
314
- <div class="col-md-1"></div>
315
- <div class="col-md-4">
316
- <h2>Typo ?</h2>
317
- </div>
318
- </div>
319
- <?php
320
- foreach ($helper->get_spellchecks() as $feed => $suggestions) {
321
- ?>
322
- <div class="row">
323
- <div class="col-md-6">
324
- <h4><?php echo $feed ?></h4>
325
- <ul class="list-unstyled">
326
- <?php
327
- foreach ($suggestions as $suggest) {
328
- ?>
329
- <li>
330
- <h3>Did you mean...</h3>
331
- <p><a href="<?php echo $suggest->get_link() ?>"><?php echo $suggest->get_formatted_text() ?></a></p>
332
- </li>
333
- <?php } ?>
334
- </ul>
335
- </div>
 
 
336
  </div>
337
- <?php } ?>
338
- </div>
339
  </div>
340
  <!-- ####################### Error ########################### -->
341
  <?php } elseif ($helper->in_error()) { // no spellcheck... is there any error? ?>
342
  <div class="row">
343
- <div class="col-md-9">
344
- <div class="row">
345
- <div class="col-md-1"></div>
346
- <div class="col-md-4">
347
- <h2>Really bad error occured</h2>
348
- </div>
349
- </div>
350
- <div class="row">
351
- <div class="col-md-10">
352
- <h2><?php echo $helper->get_error_msg() ?></h2>
353
- </div>
 
354
  </div>
355
- </div>
356
  </div>
357
  <?php } ?>
358
 
359
- <!-- jQuery (necessary for Bootstrap\'s JavaScript plugins) -->
360
- <script src="//code.jquery.com/jquery.js"></script>
361
- <!-- Include all compiled plugins (below), or include individual files as needed -->
362
- <script src="js/bootstrap.min.js"></script>
363
- </body>
364
- </html>
365
-
2
  /** @file raw_example.php
3
  * @example raw_example.php
4
  */
 
5
  require_once "PHP_API/afs_lib.php";
 
6
  $search = new AfsSearch('eval.partners.antidot.net', 48000);
 
7
  $query = $search->build_query_from_url_parameters();
8
  $query = $query->set_lang('fr'); // language is set manually in order to get spellcheck results
9
  $query = $query->set_multi_selection_facets('classification');
10
  $query = $query->set_mono_selection_facets('afs:lang', 'has_variants', 'has_image');
11
  $query = $query->set_facet_order('price_eur', 'marketing', 'classification', 'has_variants', 'has_image');
12
  $query = $query->set_facets_values_sort_order(AfsFacetValuesSortMode::ITEMS, AfsSortOrder::DESC);
 
13
  $helper = $search->execute($query);
14
  $generated_url = $search->get_generated_url();
 
15
  $clustering_is_active = $query->has_cluster();
16
  $nsmap = array('ns' => 'http://ref.antidot.net/store/afs#');
 
17
  ?>
18
 
19
 
20
  <html>
21
+ <head>
22
  <title>Antidot PHP API - Raw example</title>
23
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
24
  <meta charset="UTF-8">
26
  <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-theme.min.css">
27
  <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
28
  <!--[if lt IE 9]>
29
+ <script src="../../assets/js/html5shiv.js"></script>
30
+ <script src="../../assets/js/respond.min.js"></script>
31
  <![endif]-->
32
+ </head>
33
+ <body>
34
+ <div>
35
  <a href="<?php echo $generated_url; ?>" target="_blank"><?php echo $generated_url; ?></a>
36
+ </div>
37
+ <div class="page-header">
38
+ <h1>Raw example <small>based on the Antidot PHP API</small></h1>
39
+ </div>
40
+ <!-- ####################### Search box ########################### -->
41
+ <div class="row">
42
+ <div class="col-md-5"></div>
43
+ <div class="input-group col-md-2">
44
  <form method="get" action="" role="form" class="input-group">
45
+ <span class="input-group-addon">Search</span>
46
+ <input type="search" name="query" class="form-control" placeholder="Keywords" />
47
  <span class="input-group-btn">
48
  <button class="btn btn-primary" type="submit"><span class="glyphicon glyphicon-search"></span></button>
49
  </span>
50
  </form>
 
51
  </div>
52
+ </div>
53
 
54
+ <!-- ####################### Current filter parameters ########################### -->
55
  <?php
56
  $params = $query->get_parameters(false);
57
  if (array_key_exists('filter', $params) && is_array($params['filter'])) {
73
  </div>';
74
  } ?>
75
 
76
+ <!-- ####################### Promote ########################### -->
77
  <?php
78
  if ($helper->has_promote()) {
79
  echo '
106
  // checks whether there is at least one replyset
107
  if ($helper->has_replyset()) {
108
  $replyset = $helper->get_replyset(); // Retrieves only first replyset
 
109
  if ($replyset->has_facet()) {
110
+ /* if (in_array('facets', $replyset)) */
111
+ ?>
112
+ <div class="row">
113
+ <div class="col-md-3">
114
+ <h2>Filters</h2>
115
+ <!-- ####################### Filters ########################### -->
116
+ <?php
117
+ foreach ($replyset->get_facets() as $facet) {
118
+ /* foreach ($replyset->facets->facet as $facet) */
119
+ ?>
120
+ <div class="panel panel-default">
121
+ <div class="panel-heading"><?php echo $facet->get_label() ?></div> <!-- $facet->labels[0]->label -->
122
+ <div class="panel-body">
123
+ <div class="list-group">
124
+ <div class="list-group">
125
+ <?php
126
+ foreach ($facet->get_elements() as $value) {
127
+ /* $item = null;
128
+ * if ($facet->{'afs:t'} == 'FacetTree') {
129
+ * $item = 'node';
130
+ * } elif ($facet->{'afs:t'} == 'FacetInterval') {
131
+ * $item = 'interval;
132
+ * } else {
133
+ * throw new Exception('Unknown facet layout: ' . $facet->{'afs:t'});
134
+ * }
135
+ * foreach ($facet->$item as $value) */
136
+ ?>
137
+ <a class="list-group-item <?php echo ($value->active ? 'active' : '') ?>" href="<?php echo $value->link ?>"><?php echo $value->label ?><span class="badge"><?php echo $value->count ?></span></a>
138
+ <!-- $active = $query->has_filter($facet->id, $value->key);
139
+ ...
140
+ -->
141
+ <?php } ?>
142
+ </div>
143
+ </div>
144
+ </div>
145
  </div>
146
+ <?php } ?>
147
+ </div>
148
+ <?php } ?>
 
 
149
 
150
+ <div class="col-md-9">
151
+ <div class="row page-header">
152
+ <div class="col-md-1"></div>
153
+ <div class="col-md-2">
154
+ <h2>Results <span class="label label-success"><?php echo $replyset->get_meta()->get_total_replies() ?></span></h2>
155
+ <h4><span class="label label-info">Duration <?php echo $replyset->get_meta()->get_duration() ?> ms</span></h4>
156
+ </div>
157
+ <div class="col-md-1"></div>
158
+ <div class="col-md-2">
159
+ <!-- ####################### Relevance ########################### -->
160
+ <?php
161
+ if ($query->has_sort(AfsSortBuiltins::RELEVANCE)) {
162
+ if ($query->get_sort_order(AfsSortBuiltins::RELEVANCE) == AfsSortOrder::ASC) {
163
+ $relevance_icon = 'glyphicon-arrow-up';
164
+ $relevance_query = $query->add_sort(AfsSortBuiltins::RELEVANCE, AfsSortOrder::DESC);
165
+ } else {
166
+ $relevance_icon = 'glyphicon-arrow-down';
167
+ $relevance_query = $query->add_sort(AfsSortBuiltins::RELEVANCE, AfsSortOrder::ASC);
168
+ }
169
+ } else {
170
+ $relevance_query = $query->add_sort(AfsSortBuiltins::RELEVANCE, AfsSortOrder::ASC);
171
+ $relevance_icon = 'glyphicon-arrow-down';
172
+ }
173
+ $relevance_link = $search->get_helpers_configuration()->get_query_coder()->generate_link($relevance_query);
174
+ ?>
175
+ <a href="<?php echo $relevance_link ?>" class="btn btn-default btn-lg active" role="button"><span class="glyphicon <?php echo $relevance_icon; ?>"></span> Relevance</a>
176
+ </div>
177
+ <div class="col-md-2">
178
+ <?php
179
+ $query_coder = $search->get_helpers_configuration()->get_query_coder();
180
+ if ($clustering_is_active) {
181
+ $cluster_query = $query->unset_cluster();
182
+ $cluster_link = $query_coder->generate_link($query->unset_cluster());
183
+ $cluster_label = 'Remove clusters';
184
+ } else {
185
+ $cluster_link = $query_coder->generate_link($query->set_cluster('marketing', 1)->set_overspill());
186
+ $cluster_label = 'Create cluster on "marketing" filter';
187
+ } ?>
188
+ <a href="<?php echo $cluster_link ?>" class="btn btn-default btn-lg active" role="button"><?php echo $cluster_label ?></a>
189
+ </div>
190
+ </div>
191
 
192
+ <!-- ####################### Clusters ########################### -->
193
+ <?php
194
+ if ($clustering_is_active) {
195
+ foreach ($replyset->get_clusters() as $cluster) {
196
+ echo '
197
  <div class="row">
198
  <div class="col-md-1"></div>
199
  <div class="col-md-5">
205
  </div>
206
  </div>
207
  <ul class="list-unstyled">';
208
+ foreach ($cluster->get_replies() as $reply) {
209
+ echo '
210
  <li>
211
  <h3>' . $reply->get_title() . '</h3>
212
  <p><a href="' . $reply->get_uri() . '">' . $reply->get_uri() . '</a></p>
218
  <li>Prices:
219
  <ul>';
220
  // Here multiple values are retrieved from client data
221
+ foreach ($reply->get_clientdata()->get_values('/ns:product/ns:prices/ns:price', $nsmap) as $value)
222
+ echo '<li>' . $value . '</li>';
223
+ echo '
224
  </ul>
225
  </li>
226
  </ul>
227
  </p>
228
  </li>';
229
+ }
230
+ echo '
231
  </ul>';
232
+ }
233
+ echo '
 
234
  <div class="row">
235
  <div class="col-md-1"></div>
236
  <div class="col-md-5">
237
  <h3><span class="label label-success">Other results</span></h3>
238
  </div>
239
  </div>';
240
+ } ?>
241
 
242
+ <!-- ####################### Replies ########################### -->
243
+ <?php
244
+ echo '
245
  <ul class="list-unstyled">';
246
+ foreach ($replyset->get_replies() as $reply) {
247
+ ?>
248
+ <li>
249
+ <h3><?php echo $reply->get_title() ?></h3>
250
+ <p><a href="<?php echo $reply->get_uri() ?>"><?php echo $reply->get_uri() ?></a></p>
251
+ <p><?php echo $reply->get_abstract() ?></p>
252
+ <p>Some client data:
253
  <ul>
254
+ <li>Name: <?php echo $reply->get_clientdata()->get_value('/ns:product/ns:name', $nsmap) ?></li>
255
+ <li>Availability: <?php echo $reply->get_clientdata()->get_value('/ns:product/ns:is_available', $nsmap) ?></li>
256
+ <li>Prices:
257
+ <ul>
258
+ <?php
259
+ // Here multiple values are retrieved from client data
260
+ foreach ($reply->get_clientdata()->get_values('/ns:product/ns:prices/ns:price', $nsmap) as $value) {
261
+ echo '<li>' . $value . '</li>';
262
+ } ?>
263
+ </ul>
264
+ </li>
265
  </ul>
266
+ </p>
267
+ </li>
268
+ <?php } ?>
269
+ </ul>
270
+ </div>
271
  </div>
272
 
273
  <!-- ####################### Pager ########################### -->
274
+ <?php
275
+ if ($replyset->has_pager()) {
276
+ $pager = $replyset->get_pager();
277
+ ?>
278
+ <div class="row">
279
+ <div class="row">
280
+ <div class="col-md-5"></div>
281
+ <div class="input-group col-md-3">
282
+ <ul class="pagination">
283
+ <?php
284
+ foreach ($pager->get_all_pages() as $page => $url) {
285
+ if ($page == $pager->get_current_no()) {
286
+ $active = 'active';
287
+ } else {
288
+ $active = '';
289
+ }
290
+ ?>
291
+ <li class="<?php echo $active ?>"><a href="<?php echo $url ?>"><?php echo $page ?></a></li>
292
+ <?php } ?>
293
 
294
+ </ul>
295
+ </div>
296
  </div>
297
+ <?php } ?>
 
298
 
299
  </div>
300
 
301
  <!-- ####################### Spellcheck ########################### -->
302
  <?php } elseif ($helper->has_spellcheck()) { // if no replyset, let's check spellcheck ?>
303
  <div class="row">
304
+ <div class="col-md-9">
305
+ <div class="row">
306
+ <div class="col-md-1"></div>
307
+ <div class="col-md-4">
308
+ <h2>Typo ?</h2>
309
+ </div>
310
+ </div>
311
+ <?php
312
+ foreach ($helper->get_spellchecks() as $feed => $suggestions) {
313
+ ?>
314
+ <div class="row">
315
+ <div class="col-md-6">
316
+ <h4><?php echo $feed ?></h4>
317
+ <ul class="list-unstyled">
318
+ <?php
319
+ foreach ($suggestions as $suggest) {
320
+ ?>
321
+ <li>
322
+ <h3>Did you mean...</h3>
323
+ <p><a href="<?php echo $suggest->get_link() ?>"><?php echo $suggest->get_formatted_text() ?></a></p>
324
+ </li>
325
+ <?php } ?>
326
+ </ul>
327
+ </div>
328
+ </div>
329
+ <?php } ?>
330
  </div>
 
 
331
  </div>
332
  <!-- ####################### Error ########################### -->
333
  <?php } elseif ($helper->in_error()) { // no spellcheck... is there any error? ?>
334
  <div class="row">
335
+ <div class="col-md-9">
336
+ <div class="row">
337
+ <div class="col-md-1"></div>
338
+ <div class="col-md-4">
339
+ <h2>Really bad error occured</h2>
340
+ </div>
341
+ </div>
342
+ <div class="row">
343
+ <div class="col-md-10">
344
+ <h2><?php echo $helper->get_error_msg() ?></h2>
345
+ </div>
346
+ </div>
347
  </div>
 
348
  </div>
349
  <?php } ?>
350
 
351
+ <!-- jQuery (necessary for Bootstrap\'s JavaScript plugins) -->
352
+ <script src="//code.jquery.com/jquery.js"></script>
353
+ <!-- Include all compiled plugins (below), or include individual files as needed -->
354
+ <script src="js/bootstrap.min.js"></script>
355
+ </body>
356
+ </html>
 
lib/antidot/rules.mk CHANGED
@@ -20,7 +20,7 @@ local_test:
20
  then \
21
  if [ "${TEST_DIR}" != "" ]; \
22
  then \
23
- phpunit -d display_errors=1 -d display_startup_errors=1 -d error_reporting=-1 --stop-on-failure --include-path $(ROOT_PATH) $(CURDIR) || exit 1; \
24
  fi; \
25
  else \
26
  echo 'You need phpunit installed on your computer to run unit tests'; \
@@ -36,7 +36,7 @@ local_individual_tests:
36
  echo "\n=============================================="; \
37
  echo ">>>> Running tests for $${file} <<<<"; \
38
  echo "=============================================="; \
39
- phpunit --stop-on-failure --include-path $(ROOT_PATH) $${file} || exit 1; \
40
  done; \
41
  fi; \
42
  else \
@@ -47,7 +47,7 @@ test_coverage:
47
  @if [ -f $(which phpunit) ]; \
48
  then \
49
  rm -rf $(ROOT_PATH)/coverage; \
50
- phpunit -d display_errors=1 -d display_startup_errors=1 -d error_reporting=-1 --coverage-html=$(ROOT_PATH)/coverage --stop-on-failure --include-path $(ROOT_PATH) $(ROOT_PATH) || exit 1; \
51
  else \
52
  echo 'You need phpunit installed on your computer to run unit tests'; \
53
  fi
20
  then \
21
  if [ "${TEST_DIR}" != "" ]; \
22
  then \
23
+ phpunit -d display_errors=1 -d display_startup_errors=1 -d error_reporting=-1 --stop-on-failure --stderr --include-path $(ROOT_PATH) $(CURDIR) || exit 1; \
24
  fi; \
25
  else \
26
  echo 'You need phpunit installed on your computer to run unit tests'; \
36
  echo "\n=============================================="; \
37
  echo ">>>> Running tests for $${file} <<<<"; \
38
  echo "=============================================="; \
39
+ phpunit --stop-on-failure --stderr --include-path $(ROOT_PATH) $${file} || exit 1; \
40
  done; \
41
  fi; \
42
  else \
47
  @if [ -f $(which phpunit) ]; \
48
  then \
49
  rm -rf $(ROOT_PATH)/coverage; \
50
+ phpunit -d display_errors=1 -d display_startup_errors=1 -d error_reporting=-1 --coverage-html=$(ROOT_PATH)/coverage --stop-on-failure --stderr --include-path $(ROOT_PATH) $(ROOT_PATH) || exit 1; \
51
  else \
52
  echo 'You need phpunit installed on your computer to run unit tests'; \
53
  fi
package.xml CHANGED
@@ -1,7 +1,7 @@
1
  <?xml version="1.0"?>
2
  <package>
3
  <name>Antidot_Antidot</name>
4
- <version>1.1.0</version>
5
  <stability>stable</stability>
6
  <license>LGPL</license>
7
  <channel>community</channel>
@@ -17,9 +17,9 @@ Prevent to export empty categories node&amp;#xD;
17
  Add cdata for variant name&amp;#xD;
18
  Add variant details for grouped products</notes>
19
  <authors><author><name>Antidot</name><user>antidot</user><email>contact@antidot.net</email></author><author><name>Antidot</name><user>antidot</user><email>contact@antidot.net</email></author></authors>
20
- <date>2015-05-12</date>
21
- <time>09:47:33</time>
22
- <contents><target name="mage"><dir name="shell"><file name="antidotExport.php" hash="84b760a0cab3cc225ff8b50d6d25ed61"/><file name="antidotExportCategory.php" hash="87ebde88a80a1eb1f919aca67a69984b"/><file name="antidotExportInc.php" hash="437d19933543a58c8becd250613e5c26"/><file name="antidotExportProduct.php" hash="62c1fda71a6929d6e19864df9654c8a9"/></dir><dir name="i18n"><file name="de_DE" hash="f166a5ff29213a44fca77277b053897e"/><file name="en_US" hash="63c821044fda6f7c2a26dc84670b25bd"/><file name="es_ES" hash="f9319039054998955d63d51ed0930f3f"/><file name="fr_FR" hash="632367797f2fa9fef06e0b0c69377e01"/><file name="i18n.php" hash="0780b44563432f6e70de78f7a9d60f54"/></dir></target><target name="magecommunity"><dir name="MDN"><dir name="Antidot"><dir name="Block"><dir name="Catalog"><dir name="Layer"><dir name="Filter"><file name="Attribute.php" hash="2158b991ccdf394c8cd47cab00829e4d"/><file name="Boolean.php" hash="d17b08e1ec9047cf4050442ababd0808"/><file name="Category.php" hash="78cb53233ad74a2b5496d6f7857d8837"/><file name="Decimal.php" hash="75b31617bca2a8f20ee7fe113e3534f2"/><file name="Price.php" hash="244068a33e8ba64423c126baf883d2b5"/></dir><file name="View.php" hash="bbdd9bb31663415001ab3751c6737cde"/></dir></dir><dir name="Catalogsearch"><file name="Category.php" hash="e9605415ba85929115a443b1b4f00ab0"/><dir name="Layer"><dir name="Filter"><file name="Attribute.php" hash="2b274bf7d8f8dbd915bdf73f65e694fc"/></dir></dir><file name="Layer.php" hash="52a903855aa9cb7211eb0932d01368af"/><file name="Result.php" hash="8aaa0be7830f41616e266b2c7928604e"/></dir><dir name="Html"><file name="Select.php" hash="fc7fb19df1dd378d4e9e0860d2d47d07"/></dir><dir name="System"><dir name="Config"><dir name="Button"><file name="AfsStore.php" hash="c68e3a42a701267e9371972da60c22cb"/><file name="PushArticles.php" hash="a0cae65b4aba9b539421c0a6d06fb406"/><file name="PushCategories.php" hash="50e4b74388e1c5a65249c71dfae69400"/><file name="PushProducts.php" hash="bac543e1b17f91a558adef5da3012e28"/><file name="RestoreTemplate.php" hash="ffbbb0a73ff1ede611262a6a4da1a188"/><file name="ShowXml.php" hash="417ba0c9c62d8070b63f90397887dcc0"/></dir><dir name="Form"><dir name="Field"><dir name="Array"><file name="Additional.php" hash="acbde0308213fa976f55934fb45aba60"/><file name="AdditionalFeed.php" hash="b4489921424513278869ece9bbcd09be"/><file name="ArticleAdditional.php" hash="38c62d610f585c460151841f7350348b"/><file name="ArticleIdentifier.php" hash="ec9479fd1ca087a1fe924795cc9ff5f6"/><file name="DefaultSort.php" hash="61dec4828212e7a145b6eeda5c476858"/><file name="Facet.php" hash="dab308e0ac79a89be8d72e487739031e"/><file name="Identifier.php" hash="294c5d3bda7dae5637eabfdfdb08afc7"/><file name="ProductAdditionalFacet.php" hash="208e01078409951327f1794e17e11e89"/><file name="ProductAdditionalField.php" hash="9c9f9c9c1c940963e1a24c039a392cc4"/><file name="ProductIdentifier.php" hash="d30809119cb35018697533075f7ee485"/><file name="Sort.php" hash="6ece671c902cf6f5db66652a2c51e79f"/></dir><file name="CategoryAttribute.php" hash="1ba0dd22410eb27d18ac77b51f78ac49"/><file name="ProductAttribute.php" hash="3acbdaee390ce50e18d0ede1d641255d"/></dir></dir><dir name="Html"><file name="Export.php" hash="7cb82e5f21c769e5b39efc0be7b76473"/><file name="ShowXml.php" hash="7b70f39937aa9d24336edde6bdbdf97c"/><file name="Version.php" hash="34c624c382f3061cf322cfed52c416ac"/></dir></dir></dir></dir><dir name="Helper"><file name="Antidot.php" hash="7bbd2866c65a847e1415badb1ef0d015"/><dir name="CatalogSearch"><file name="Data.php" hash="81cc908609e68035d5714488f913e688"/></dir><file name="Compress.php" hash="9c057cf9d594b07e6d36c1142b9ceae6"/><file name="Data.php" hash="a0695759c4de3f81a07e46784761b7b2"/><dir name="Enterprise"><dir name="Search"><file name="Data.php" hash="8bfe0146c64511f86cb796638b65112f"/></dir></dir><file name="LogExport.php" hash="6d6b262327bf1d920fc2b5b112edfef6"/><dir name="ManaFilters"><file name="Data.php" hash="e5dd65e6e52c03427aa68528cc1f140a"/></dir><file name="Url.php" hash="1d2ee02a8e135bfc4b866f5219f62acd"/><file name="XmlWriter.php" hash="77addcc2f245646c50c3da4bcee16774"/></dir><dir name="Model"><dir name="Catalog"><dir name="Layer"><dir name="Filter"><file name="Attribute.php" hash="3cd18414abccea60c5497931bc95e21e"/><file name="Boolean.php" hash="dd0414e0d96833bec6e32aac321c2763"/><file name="Category.php" hash="9224a05ffa914bfcaded1c6c52bd92f9"/><file name="Decimal.php" hash="b9b1e2cff1d0332fab77d101dca4c3d2"/><file name="Item.php" hash="f7cd6f73001c61046277a4807c37c73b"/><file name="Price.php" hash="7529be0313a19896993f92eeb9dfc8a9"/></dir></dir><file name="Layer.php" hash="706000dd944a45f30826eccba2942862"/></dir><dir name="Catalogsearch"><dir name="Layer"><dir name="Filter"><file name="Attribute.php" hash="a83d6761a949c8196cba33948a48c8bf"/></dir></dir><file name="Layer.php" hash="1425db54170c23fc23e579284e4e1418"/><dir name="Resource"><file name="Attribute.php" hash="80d2a34d746f307109b6bf910b0f2958"/></dir></dir><dir name="Export"><file name="Abstract.php" hash="38d6d6dbb68872d0c46e26c61c38c30e"/><file name="Article.php" hash="91ea6e7acae1519413711abfc076ad0c"/><file name="Category.php" hash="a326b576f9a5f0f90cb5f57f3f155b26"/><file name="Product.php" hash="197f7ba0fe7f96808f2676d31313df22"/></dir><file name="Observer.php" hash="8d7d35c1362b1597a773a749377f9b28"/><dir name="Resource"><file name="Advanced.php" hash="f4810c1af8d5a15f7a424d7baf5fc777"/><dir name="Catalog"><dir name="Product"><file name="Collection.php" hash="144dd8688830992c9300d420ed203a23"/></dir></dir><dir name="Engine"><file name="Abstract.php" hash="6ad534401be39ac25229b11fea341804"/><file name="Antidot.php" hash="8b9b768bb91471260e927d33879b85c0"/></dir></dir><dir name="Search"><file name="Abstract.php" hash="fd71154b987b16f8d13bc3e10a3faeac"/><file name="Search.php" hash="aeef203f9a3794e9ae1e35a825f0eca3"/><file name="Suggest.php" hash="86586ee73cbc7aee0aef8c81d92fb34e"/></dir><dir name="System"><dir name="Config"><file name="ArticleAttribute.php" hash="f3a9596d45f275299f16530a56845c96"/><dir name="Backend"><file name="Engine.php" hash="68c93651655a77c74fd79d1de6d19be3"/></dir><file name="CategoryAttribute.php" hash="9f19b99e16c99b0e8052b1e31d2a6317"/><file name="Dir.php" hash="c80d83280ebc5ab91fd45d246ec47ba3"/><file name="DisableEnable.php" hash="6d08f33a1580b2fd1d58d87248104166"/><file name="Engine.php" hash="a3703b427ee777ce4ea58c8b31604158"/><file name="Facet.php" hash="84e108c99b57f88f6ce73931e5db0944"/><file name="Number.php" hash="7985ea6c495a35173d68291389319f93"/><file name="Options.php" hash="06930da994dec4bb05ebc3f3e8c8abb8"/><file name="ProductAttribute.php" hash="c74ad00177c3a12b03c8684928d12c40"/><file name="PromoteRedirect.php" hash="c167973ea7a0ef09f0e5fa0fd0a08926"/><file name="Sort.php" hash="608358f239a483a8b5b3217284c14896"/><dir name="Suggest"><file name="Type.php" hash="cef491efdb9fcef86d0df75030206a78"/></dir><file name="WSStatus.php" hash="ff4954e15d75dd3139290d96773d0abf"/></dir></dir><dir name="Transport"><file name="Abstract.php" hash="3272c44b08523a9836aa15c835e2ed25"/><file name="File.php" hash="0941fd452279605a2ea6a5d40f857000"/><file name="Ftp.php" hash="8d1aa862bb8f3656bd199d5ce592e0b1"/><file name="Http.php" hash="fb80d47a6d991b9f706418061a2cbd7e"/><file name="Interface.php" hash="32d1d3958e0cd726bc34cae482464ef8"/></dir><file name="Transport.php" hash="de133bf273352bcafead75745fb347ba"/></dir><dir name="Test"><dir name="Block"><dir name="System"><dir name="Config"><dir name="Button"><file name="AfsStore.php" hash="dcbfefb440b8512b1298b624a3582076"/></dir></dir></dir></dir><dir name="Model"><dir name="Export"><file name="Article.php" hash="c2d43ccf7c9b6648b633d122c657f27d"/><file name="Category.php" hash="c29dbe5ffb63eae4d51e57f7ff298bd3"/><dir name="Product"><dir name="fixtures"><file name="testWriteImageUrl.yaml" hash="a4e08b8f1565eba67a16553cf57e1004"/><file name="testWriteProductUrl.yaml" hash="a4e08b8f1565eba67a16553cf57e1004"/><file name="testWriteProperties.yaml" hash="d434749b80908bbceefd5781e2d0e998"/><file name="testWriteXml.yaml" hash="c53ef98d6dea648dc63cc34ce3ee9509"/></dir><dir name="providers"><file name="testWriteImageUrl.yaml" hash="666c33585c611bcc0b0ebe6e87dce1fc"/><file name="testWriteProductUrl.yaml" hash="18f511460efea04586fc888f5c85b3ea"/></dir></dir><file name="Product.php" hash="d2f3b44893933e339db77ba0515d1c3b"/></dir><dir name="Observer"><dir name="fixtures"><file name="testGetDefaultContext.yaml" hash="e9c8aa4acd4e2c3af2e69c8eb04996bc"/></dir><dir name="providers"><file name="testGetOwnerForFilename.yaml" hash="c5c07e73f536f9ffacc0c3ff6b5a13d1"/></dir></dir><file name="Observer.php" hash="86536c523b1249b9d100a5dc40ea7793"/><dir name="Resource"><dir name="Engine"><file name="Antidot.php" hash="7e59165d905a8679fe282a9dd8d0e285"/></dir></dir><dir name="System"><dir name="Config"><dir name="Sort"><dir name="expectations"><file name="testToOptionArray.yaml" hash="13fc5b4c17962fb267f443d03a2219b2"/></dir><dir name="fixtures"><file name="testToOptionArray1.yaml" hash="f1e09ff12a4c13817d3aafd9254d3f7c"/><file name="testToOptionArray2.yaml" hash="160c861aa7adf28b4d3dc1423dcc8d84"/><file name="testToOptionArray3.yaml" hash="bbb2d78972449929cac497c62ec6fef8"/></dir></dir><file name="Sort.php" hash="8173c08ae65d529ace25a745ffd4b3e6"/></dir></dir></dir><file name="PHPUnitUtil.php" hash="2a128a7c19f4c37cb9dd7fc60e679693"/></dir><dir name="controllers"><dir name="Admin"><file name="PushController.php" hash="fb131afc3d26e5e591968e8fa3ed5375"/></dir><dir name="Front"><file name="SearchController.php" hash="474f1bd0136e3bdea38e9991df361679"/></dir></dir><dir name="etc"><file name="config.xml" hash="ad7a33972038da10d70414ba4be650db"/><file name="system.xml" hash="f6e7ac229fe171ef4896ea9c97643aef"/></dir><dir name="sql"><dir name="Antidot_setup"><file name="mysql4-install-0.9.php" hash="62672bc47ea92dbd46966fb76e4251e0"/></dir></dir></dir></dir></target><target name="magedesign"><dir name="frontend"><dir name="base"><dir name="default"><dir name="template"><dir name="antidot"><dir name="catalog"><dir name="layer"><file name="category.phtml" hash="3ec81f7b3e3b947317da8664c8e15927"/><file name="filter.phtml" hash="2304baebff9b798e0ebd977fbc891346"/></dir></dir><dir name="catalogsearch"><file name="result.phtml" hash="12c082ddff0e6c4fef74630b8253face"/></dir></dir></dir></dir></dir><dir name="default"><dir name="default"><dir name="layout"><file name="antidot.xml" hash="654b0cbb9d7c3f7a0a506e3f6adf164b"/></dir><dir name="template"><dir name="antidot"><dir name="catalogsearch"><dir name="result"><file name="category.phtml" hash="7413580b825508f2cfc08566d62369ae"/></dir></dir></dir></dir></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="MDN_Antidot.xml" hash="988c6b7e9da4e50f1727956833ab1696"/></dir></target><target name="magelocale"><dir name="de_AT"><file name="MDN_Antidot.csv" hash="f73ff4aa6f983793957a6b295e8e6488"/></dir><dir name="de_CH"><file name="MDN_Antidot.csv" hash="f73ff4aa6f983793957a6b295e8e6488"/></dir><dir name="de_DE"><file name="MDN_Antidot.csv" hash="f73ff4aa6f983793957a6b295e8e6488"/></dir><dir name="es_AR"><file name="MDN_Antidot.csv" hash="7a6a749b1da8b3fca7823e8b08f53add"/></dir><dir name="es_CL"><file name="MDN_Antidot.csv" hash="7a6a749b1da8b3fca7823e8b08f53add"/></dir><dir name="es_CO"><file name="MDN_Antidot.csv" hash="7a6a749b1da8b3fca7823e8b08f53add"/></dir><dir name="es_CR"><file name="MDN_Antidot.csv" hash="7a6a749b1da8b3fca7823e8b08f53add"/></dir><dir name="es_ES"><file name="MDN_Antidot.csv" hash="7a6a749b1da8b3fca7823e8b08f53add"/></dir><dir name="es_MX"><file name="MDN_Antidot.csv" hash="7a6a749b1da8b3fca7823e8b08f53add"/></dir><dir name="es_PA"><file name="MDN_Antidot.csv" hash="7a6a749b1da8b3fca7823e8b08f53add"/></dir><dir name="es_PE"><file name="MDN_Antidot.csv" hash="7a6a749b1da8b3fca7823e8b08f53add"/></dir><dir name="es_VE"><file name="MDN_Antidot.csv" hash="7a6a749b1da8b3fca7823e8b08f53add"/></dir><dir name="fr_CA"><file name="MDN_Antidot.csv" hash="5a408d02979b224a1387c1be415caa37"/></dir><dir name="fr_FR"><file name="MDN_Antidot.csv" hash="aed12e90a30b556952e5c33dd904867a"/></dir></target><target name="mageweb"><dir name="js"><dir name="mdn"><dir name="antidot"><file name="CollapsibleLists.js" hash="86792ecde0c2759ba85e0d863dd147ce"/></dir></dir></dir></target><target name="magelib"><dir name="antidot"><dir name="AFS"><dir name="ACP"><file name="Makefile" hash="0f76232bfabc275a3dac973666fb5dae"/><dir name="TEST"><file name="Makefile" hash="ce56cc786e1df50148e1d3222c05e5f8"/><file name="acpConnectorTest.php" hash="25a8194f3dc8895640df4f4bba895d8e"/><file name="acpQueryTest.php" hash="74ad65a4af639a409ee72a75a2a043d6"/><file name="acpReplysetHelperTest.php" hash="4f0a0d471a06e139cd11c715b67ebe81"/><file name="acpResponseHelperTest.php" hash="6d30f99108db0d9956aef9ba5e1d88df"/><file name="acpTest.php" hash="d6119d150543e7943ba4e9907901ae5d"/></dir><file name="afs_acp.php" hash="78dbfbc92f68469c92898f1da4263e68"/><file name="afs_acp_configuration.php" hash="2d644cc6c5bf2cdaeca5780576c4bf0e"/><file name="afs_acp_connector.php" hash="cf872314b38a86ebe7bb56b19bce9236"/><file name="afs_acp_exception.php" hash="f610d2cc37a15d4b981d7b43939414ad"/><file name="afs_acp_query.php" hash="ced0629355f5d4fc1c219d1adb03297d"/><file name="afs_acp_query_manager.php" hash="b3348972a850c904fc664b4e27671439"/><file name="afs_acp_reply_helper.php" hash="b0259f24f10d2e92ed6e3b8cdaaacc44"/><file name="afs_acp_replyset_helper.php" hash="07e7fdb88a42a399c96261c47ffb0231"/><file name="afs_acp_response_helper.php" hash="33a66106fd3a94194514a0d8d39af1cd"/></dir><file name="Makefile" hash="7bb31592939024f74745d6b6cb7fec0b"/><dir name="SEARCH"><dir name="FILTER"><file name="Makefile" hash="d42338199c6857ded179af2117b9f571"/><dir name="TEST"><file name="Makefile" hash="ab37090c6c5e7af1b260376237737700"/><file name="filterBuilderTest.php" hash="161ff5c8e73914eef884d17456afa133"/><file name="filterCombinationTest.php" hash="2162288d5255d3b24fe94d75b939aa51"/><file name="filterTest.php" hash="1682c0a4d50158a8d2c9369d30e45a18"/><file name="groupFilterTest.php" hash="1ebe8ce7344ed64b93cf94632d3b0184"/></dir><file name="afs_combinable_filter.php" hash="336e6c6bc9ebae3f58602d23ef734182"/><file name="afs_combinator_filter.php" hash="e2fc560b9c0c31f20c73f2057a8b7b69"/><file name="afs_filter.php" hash="1efc032fd2615c82c350f69ba11860fa"/><file name="afs_filter_exception.php" hash="ccce583c63a4a65f7f0a27fc4a487505"/><file name="afs_filter_wrapper.php" hash="30dec104456abc037019ad93922b5afd"/><file name="afs_group_filter.php" hash="b95fa3bc0e26bc39dfc53a6010bce32f"/><file name="afs_operator_filter.php" hash="c7ea43c8d64eedbe33397f61737e0226"/><file name="afs_valued_filter.php" hash="483653071734f77972c9b9771e187d82"/></dir><file name="Makefile" hash="0f76232bfabc275a3dac973666fb5dae"/><dir name="TEST"><file name="Makefile" hash="ce56cc786e1df50148e1d3222c05e5f8"/><file name="clientDataHelperTest.php" hash="523abcf4ab7a42e16c39c2b02bae927c"/><file name="clusterHelperTest.php" hash="e112e7c756f63c8e8ceb554281b418c9"/><file name="conceptHelperTest.php" hash="b44e39b62d0537bf1f7b7feb23f8111f"/><file name="facetDefaultTest.php" hash="382e4ea35e1c7173371b4a84046a38e5"/><file name="facetHelperTest.php" hash="2c6fbec3f1d4dd6e37c089ac835a88b0"/><file name="facetManagerTest.php" hash="bbef8e207c387dbe6a26142fd55264d5"/><file name="facetTest.php" hash="f0264af2550394a4a3d944bc86dac667"/><file name="facetValuesSortOrderTest.php" hash="b650080bf9b2cce2ac42a245cb84c911"/><file name="feedCoderTest.php" hash="f2b5dfdd4fa3c4e5d14c790d15235146"/><file name="filterCoderTest.php" hash="46249fa13edccf1e5d5000daf2573b77"/><file name="headerHelperTest.php" hash="62185c34e1e9015bb12014d719287f06"/><file name="helperConfigurationTest.php" hash="be3f74e53e27744e8214f3c341172796"/><file name="intervalTest.php" hash="912389dad049853f6bf0b4eab2af5034"/><file name="metaHelperTest.php" hash="080f160b54636c4eee743544a6a12bee"/><file name="pagerHelperTest.php" hash="b756d39c29c1d3cfb2733ab13062542e"/><file name="promoteReplyHelperTest.php" hash="7cbb68a7f50c2bd2ef11a085ac94deb2"/><file name="promoteReplysetHelperTest.php" hash="749180b072997539d322c88c97c586d6"/><file name="queryCoderTest.php" hash="064979c30a7e215c486e34abce79b1b5"/><file name="queryTest.php" hash="c48bc5a88a788bbc4a26604b86d60454"/><file name="replyHelperTest.php" hash="5b3cfec02c640282bf4fec92353801d6"/><file name="replysetHelperTest.php" hash="fdb55d9a09f9198fb26b5fab3edc58c3"/><file name="responseHelperTest.php" hash="35969ff7882d97b93aa874fafd4b55c3"/><file name="searchConnectorTest.php" hash="9201de573884b643041b6c32bc535e7e"/><file name="searchQueryManagerTest.php" hash="2334d06f4247abfd69c2b4dc842cc404"/><file name="searchTest.php" hash="eeb7a86bd5b48108434fb93da4e0c0f2"/><file name="spellcheckHelperTest.php" hash="49960fb90055dcf265ef41e491c11325"/><file name="spellcheckTextVisitorTest.php" hash="203f0d08f548a39135517a41f6e9e43a"/><file name="textVisitorTest.php" hash="b722845dd0f5f953574cb51284ad025b"/></dir><file name="afs_base_reply_helper.php" hash="c1c3961f3cc03924fda382adf6e6c419"/><file name="afs_base_replyset_helper.php" hash="096b124a3ebdc6e8d6beb359bd8bb7c5"/><file name="afs_client_data_exception.php" hash="899957af974d04aa7eaca44903a7f86c"/><file name="afs_client_data_helper.php" hash="b2383fc244d6bbcda6de7387ae7b1b0d"/><file name="afs_cluster_exception.php" hash="86d97623db7aebaa28a20857ce2cf17f"/><file name="afs_cluster_helper.php" hash="60b7fbcc869a672929ef9fc6d840d2b2"/><file name="afs_coder_base.php" hash="fb87fbea43d12695154b3b6102e2a019"/><file name="afs_coder_interface.php" hash="3b179b2513e215751ee4edd190b2a719"/><file name="afs_concept_helper.php" hash="982cf3d2063c565cf19cc6136b049066"/><file name="afs_count.php" hash="9f83f3baa3cf4462c0db786f4eea479a"/><file name="afs_facet.php" hash="b5d89249e71741b0558dbb762ad1a077"/><file name="afs_facet_combination.php" hash="005e9742ee032194b86856195dd59f7d"/><file name="afs_facet_default.php" hash="cbcb5d28b7b00815ce5248017065e84b"/><file name="afs_facet_exception.php" hash="f1f0afdbf9a727b53c4731e5a40ac417"/><file name="afs_facet_helper.php" hash="63bf1e4b92cf1e1bdf06b7da54afd5f9"/><file name="afs_facet_helper_retriever.php" hash="5628cc41c50ab25fd3336df302d903f4"/><file name="afs_facet_layout.php" hash="c83f6fef1c13ba3cda667c611841ff87"/><file name="afs_facet_manager.php" hash="3f022435274cbb500699ea054461f4bf"/><file name="afs_facet_mode.php" hash="17f17d277168a017e66364be5ac85394"/><file name="afs_facet_sort.php" hash="0d7ba4059b10da9981b9c801355cb874"/><file name="afs_facet_type.php" hash="6df82cbfa627629f9523437994d1fbb1"/><file name="afs_facet_value_formatter.php" hash="d6580281f9ef5c0820615ac385aae863"/><file name="afs_facet_values_sort_mode.php" hash="17def98365132c810515f8cf3c6fb006"/><file name="afs_facet_values_sort_order.php" hash="f95f77cb5dd7015e4f2e6094ddba49a6"/><file name="afs_feed_coder.php" hash="0df08c2d4e30c9b99d56ce7fdbc1b40b"/><file name="afs_filter_coder.php" hash="6a528ece8d5999aab9eb0fffabea25e3"/><file name="afs_header_helper.php" hash="3b30d839efe9128773c82d47cbd591b8"/><file name="afs_helper_configuration.php" hash="dbd0378574fbc5729babfbddfef0fd67"/><file name="afs_interval.php" hash="dbf9749881be0a2b063f8a33dff214f3"/><file name="afs_interval_exception.php" hash="40f223de231df03aae59596c1a493065"/><file name="afs_meta_helper.php" hash="8403689868c98db725ebd11748508c8b"/><file name="afs_pager_helper.php" hash="8e93f8c060d2fedabbcbad5607a27807"/><file name="afs_producer.php" hash="7c8c515ccb8126523fa0d09a7f759dd5"/><file name="afs_promote_reply_helper.php" hash="b582c3064f0dff62514e28e91d715cf9"/><file name="afs_promote_replyset_helper.php" hash="fdefc6f8a686addb31ea9b6c0a3fa5ad"/><file name="afs_query.php" hash="015bc3e7d007943708f064a34582d6ef"/><file name="afs_query_coder.php" hash="87021c05f45168f11eae4045b999b347"/><file name="afs_query_coder_interface.php" hash="dd16f17b3606a7418c1c714475b19b51"/><file name="afs_query_object_interface.php" hash="a9af13e2c856e4136ccadfff60f72d36"/><file name="afs_raw_text_visitor.php" hash="fd574583c4c9110165c1cadc67b832de"/><file name="afs_reply_helper.php" hash="04a65217b88a53a951d687455986b2a6"/><file name="afs_reply_helper_factory.php" hash="119fba6f39a19ef27fb8c864158cc7a2"/><file name="afs_replyset_helper.php" hash="190b08443559c28a204e8cfb6826d441"/><file name="afs_response_exception.php" hash="0a865bb92fb700ae555dcb5ae675f644"/><file name="afs_response_helper.php" hash="1805fd45c11ef77121867bb84850bedd"/><file name="afs_search.php" hash="11770cf52edd84331988bf61228ab24a"/><file name="afs_search_connector.php" hash="17242fb6536f4596b2c0198a16986310"/><file name="afs_search_query_manager.php" hash="91ee821f87eaeb9f14d5313a19b3f807"/><file name="afs_sort_builtins.php" hash="0cc1617a62f1a834a28d7d2ac249b081"/><file name="afs_sort_coder.php" hash="543015ed1d40caa40317a231476ea06c"/><file name="afs_sort_order.php" hash="7755deb99386650c9974871474168cda"/><file name="afs_spellcheck_helper.php" hash="bb5465848ada7a9df9875f2565fb9686"/><file name="afs_spellcheck_text_helper.php" hash="3ca5c3118660aa600aadb504ceff6c4c"/><file name="afs_spellcheck_text_visitor.php" hash="c44c23ae21f61b065e457911bbc45ed2"/><file name="afs_text_helper.php" hash="59c4ae24560948c3af0f4adbf6bd1803"/><file name="afs_text_visitor.php" hash="867b44a280403cd4567358ec6d59588a"/></dir><file name="afs_configuration_base.php" hash="f26dd9efda4923cc2c71057f21be97d9"/><file name="afs_connector.php" hash="3e000a037ca1d64587a90f53dd6c888b"/><file name="afs_exception.php" hash="c1840fe279f9cb313cec151012ed4513"/><file name="afs_origin.php" hash="a6b7e39a687210572c116afcbea0e7cb"/><file name="afs_query_base.php" hash="63b8fba7bb5c17150e4af0e765deab27"/><file name="afs_response_helper_base.php" hash="b087f7bdad35ed0526566042ef9afc8c"/></dir><dir name="AIF"><file name="Makefile" hash="2d232abf9913fcabb44033d5e5d1ebfd"/><dir name="TEST"><file name="Makefile" hash="24d3030d27e88732028d14fb1d81c203"/><file name="afsMultipartResponseTest.php" hash="70a64d0d599ea01806fac2126fb3680a"/><file name="authenticationTest.php" hash="2e476e9ab15ee221ddd63bb555262a28"/><file name="bowsInformationTest.php" hash="3bbfe71f431a35f0285afdca40906874"/><file name="documentManagerTest.php" hash="ad90a6146f5aeee383355bb05425b3dd"/><file name="documentTest.php" hash="59b204b10b90cd764b259ad4c2bc043a"/><file name="pafConnectorTest.php" hash="ac2928b501d9ea167af43dbf3adafa7d"/><file name="pafLiveTest.php" hash="92862c31d151c34b2caf44bff9d0fb80"/></dir><file name="afs_about_connector.php" hash="8972264a9b7cce237ad1a4b47852b529"/><file name="afs_authentication.php" hash="4285035550c9681a047b85abbca64936"/><file name="afs_bows_connector.php" hash="47a6bcafd5eba2361d2cea409f60d3f7"/><file name="afs_bows_connector_interface.php" hash="8fdf9749f0500a39741d696feb55af14"/><file name="afs_bows_exception.php" hash="1bd8657a37b8b4a9e08bfc4eb6b7e416"/><file name="afs_bows_information.php" hash="1f96a4cd84b2332f1186f9e0cea8542d"/><file name="afs_bows_information_cache.php" hash="1ae9a9243342c4e58a52e70473b68472"/><file name="afs_document.php" hash="6a04f43252f67f6dd90cc23d03fa2b63"/><file name="afs_document_manager.php" hash="8c5c0105d9337b7ae6a9f041f643ea88"/><file name="afs_multipart_response.php" hash="f2077c9eaf121fabdb2fc26c23b2e256"/><file name="afs_paf_connector.php" hash="96111b0536c83874b7c06ada5577106b"/><file name="afs_paf_live_connector.php" hash="9efeb2716f6d95e666f9c37726869fe7"/><file name="afs_paf_upload_reply.php" hash="0cb4905d1c894637d5e6acbd2cffc112"/><file name="afs_token_authentication.php" hash="1f003310f156f0a71db1d273375172d8"/><file name="afs_user_authentication.php" hash="03deeead93ee32753f2f7f80cfc011f4"/></dir><dir name="COMMON"><file name="Makefile" hash="7bb31592939024f74745d6b6cb7fec0b"/><dir name="TEST"><file name="Makefile" hash="d568cfe3683543f363312aa4b6d2bbad"/><file name="languageTest.php" hash="ad0f75b1c2f320c81eba32cade86191c"/><file name="toolsTest.php" hash="9276cb1a275d697f8e8365f2ac340cdf"/><file name="userSessionManagerTest.php" hash="b2b78d6fa156f1a61065f8ee5bfc6e0b"/></dir><file name="afs_connector_base.php" hash="b6b1f091ec71e5b92e4a1e5ca958255f"/><file name="afs_connector_interface.php" hash="68ad5e20a861b85dbf198f79cd2afd4c"/><file name="afs_exception.php" hash="c45bcd565a4124da5d6b23a21d5845a5"/><file name="afs_helper_base.php" hash="839cca78a663c3a22b4a8e35d1460129"/><file name="afs_helper_format.php" hash="30a3f6e945db7412ef95e83e7b0b5898"/><file name="afs_language.php" hash="277acb15b86089b37c812c47f2141d3c"/><file name="afs_service.php" hash="12c00c906e130860120552c40fa9dbc2"/><file name="afs_service_status.php" hash="1dee172850a76b46987534df89013878"/><file name="afs_tools.php" hash="26f6c01c5a61987925385e7a35260399"/><file name="afs_user_session_manager.php" hash="abd625f6b7b5cecf386dac9d82887764"/><file name="afs_versions.php" hash="29dda789ed7b363dc512e3c52a9d80ce"/><dir name="php-SAI"><file name="README.md" hash="63ab581c83fe44918e6d074e20f08f95"/><dir name="lib"><dir name="Curl"><file name="Handle.php" hash="0fc7132737da7cee7df6b974447864ac"/></dir><file name="Curl.php" hash="358e4d3afca2035ee4d3f99f372ed15a"/><file name="CurlInterface.php" hash="714fa045dd4546d0c92cd022efb09422"/><file name="CurlStub.php" hash="fbdc0ece6321c5b5a1e27a65449f4a1f"/><dir name="rb_temp"><file name="HttpClient.php" hash="091b91c98acf9f1cd6c3d6d75cddfb88"/><file name="MultiCurl.php" hash="916e85d73bae6e136f889166ebc6db17"/><file name="SimpleCurl.php" hash="c296966a8bda96e03b464a1d3a9c8e06"/></dir></dir><dir name="tests"><file name="SAI_CurlStubTest.php" hash="bce69cbb17a40bd4eeba6bad1133216e"/></dir><file name=".gitignore" hash="455ed27e3ee2636761d16f833e4d3984"/></dir></dir><file name="COPYING" hash="b234ee4d69f5fce4486a80fdaf4a4263"/><file name="COPYING.LESSER" hash="4fbd65380cdd255951079008b364516c"/><file name="FAQ.md" hash="7d7c886674d70a0047303c5d93de6165"/><file name="Makefile" hash="225475a5a4a0204cecbb77621ff38bb2"/><file name="README.md" hash="c38fa0e7c5aa391c2842affdf89c4795"/><file name="afs_lib.doxygen" hash="4f5839371b1b6ba64f76029bc5865dbf"/><file name="afs_lib.php" hash="4e93523d71e8b083654ac85cb24f8c68"/><file name="afs_version.php" hash="c8db9ed5ee1881b6e31a60a471a81b8a"/><dir name="doc"><file name="afs_filter_documentation.dox" hash="3bf4b96e25d95ce5953b822038c6f135"/><file name="afs_paf_upload.dox" hash="d36893db0234f171e6cfb43f6e13d47c"/><file name="afs_search.dox" hash="b1c5ab8728703822f910852cd17561f4"/><file name="afs_search_coder.dox" hash="77709e1bc691301017f0982e0348a9b9"/><file name="afs_search_query.dox" hash="21dcd1734a165a4cb3b4f62c42a6a0be"/><file name="afs_search_reply.dox" hash="cdb1d42447671f4352927b40b3f8f37d"/><dir name="data"><file name="acp_helper_example.php" hash="2815890e7afbae78e7eb4e6fc5c88f6f"/><file name="full_example.php" hash="e152a964d06e55de460c596070c714d8"/><file name="full_lightweight_example.php" hash="eac3bb2d251052f547a9f737e5cd0461"/><file name="raw_example.php" hash="ed86e971114243f3b28fa39bcaa972b8"/><dir name="templates"><file name="error_template.html" hash="70f44bd0f45470d379a11d0a2fe507e4"/><file name="facet_template.html" hash="6836005a7dae45e9415273f1eb6b78e2"/><file name="facet_values_template.html" hash="9b41f2b55a1cecae5724b4fcd4a46cfb"/><file name="meta_template.html" hash="e664a3bb222d272ce2451fb10bf46de4"/><file name="pager_template.html" hash="2700ab5b60a1f9553b1c39374fda63d4"/><file name="result_template.html" hash="1572a4ef4e8dda0b3db1ea77bbed4a98"/><file name="spellcheck_template.html" hash="8042054a1f5a271b47c77f81436c4791"/></dir></dir><file name="detailled_integration_example_with_template.dox" hash="26ef377a6ef546b636a0e254d11d01f5"/><file name="lightweight_integration_example_with_template.dox" hash="5a388d2dbfad63ad6ec353407b79a6bb"/><file name="logo-antidot-long-200x41.png" hash="1ceac3fff767fb5e395bd767344a3d13"/><file name="main.dox" hash="ca3e97f95deead927fb3298ecafbad5e"/><file name="raw_integration_example.dox" hash="56a7126d008c2e49abdf9bf0b5ec9717"/><file name="template_prerequisites.dox" hash="baa24a943e19ff3654227850bd316abb"/><file name="templates_in_details.dox" hash="5e8db94382f1fbd6c4e0b424a9edc9a3"/></dir><file name="rules.mk" hash="9e3570d254b92d571849718d98492192"/><dir name="scripts"><file name="gen_doc.sh" hash="0f6fc60aca94da563397d3c710bd9d33"/><file name="increment_version.sh" hash="431db9c60d2f94d251be07957787fcb0"/><file name="print_version.sh" hash="a05ddc19cd27ff185721fe2bd0cffc25"/><file name="version_management.sh" hash="3d5ecd39f45ba081144b3033dbd14330"/></dir><file name=".gitignore" hash="14de6527ce1e67cea1543b75a2322165"/></dir></target><target name="mageskin"><dir name="frontend"><dir name="base"><dir name="default"><dir name="css"><dir name="mdn"><dir name="antidot"><file name="CollapsibleLists.css" hash="c956d83facc41a97bf14726dcb953edb"/></dir></dir></dir><dir name="images"><dir name="mdn"><dir name="antidot"><file name="base.gif" hash="1f71b021e061a4948d69adc4ff10ccad"/><file name="button-closed.png" hash="563b78324e0712c0902cb4f77cb9eb86"/><file name="button-open.png" hash="c710849a0d2b61ad1f0fc36c0e59d131"/><file name="button.png" hash="97f3055c5046c851eea2dad7e5227508"/><file name="cd.gif" hash="f41037663522fab5c5c31530c7fa43d8"/><file name="empty.gif" hash="df22aff6e941ff1cc577333d1712b584"/><file name="folder.gif" hash="ea16980ab437fa6ba4aba3d480e83e9e"/><file name="folderopen.gif" hash="18aa3d75315bf95bf080357733437fcc"/><file name="globe.gif" hash="d6b48614cf8dc9553e077c19197637d2"/><file name="imgfolder.gif" hash="1d488d377762e65ab4e8b691ba01e5a4"/><file name="join.gif" hash="4d5d614e0da056df815a4306d6368692"/><file name="joinbottom.gif" hash="4b3daa7f2cc584f1aac0d142275d7cba"/><file name="line.gif" hash="63ab38a6203262f15ca46c631232ea2c"/><file name="list-item-contents.png" hash="00ae24d5bc76df9eedaea597859963e4"/><file name="list-item-last-open.png" hash="615ddd71f81b240e9ed7d4e383b2c01a"/><file name="list-item-last.png" hash="e2bfb790f46855c378e50f3c0a82ea01"/><file name="list-item-open.png" hash="732d1cc59f3a488c89c624eb434eac98"/><file name="list-item-root.png" hash="5529d21e7ec68e9cb750a4895ff0b480"/><file name="list-item.png" hash="e03ec1bf3d9e16bb3005ccf8d26eaa6c"/><file name="minus.gif" hash="d647fbbd0ec410b8f3bb3357b62eedcf"/><file name="minusbottom.gif" hash="b09d684cca7135ef728141aaf2464baa"/><file name="musicfolder.gif" hash="21ece951734f23adb2f75befe1f31fc1"/><file name="nolines_minus.gif" hash="eb2243a354ffcfac93ba0fe948f7167d"/><file name="nolines_plus.gif" hash="ec92b634b63608fb4b0dbf114e3b89e1"/><file name="page.gif" hash="c25b136c1cb3bb145495c25b35d93754"/><file name="plus.gif" hash="5c55d798909c553deca31d610bd18fac"/><file name="plusbottom.gif" hash="1924ce363c38a992f888a4df48c0b274"/><file name="question.gif" hash="ea0ca196ce0ebfd625cc1210abfdec6c"/><file name="trash.gif" hash="6cbfd3ed29531044aed9b4edb3cca9ad"/></dir></dir></dir></dir></dir></dir></target></contents>
23
  <compatible/>
24
  <dependencies><required><php><min>5.2.0</min><max>5.6.0</max></php><extension><name>curl</name><min/><max/></extension></required></dependencies>
25
  </package>
1
  <?xml version="1.0"?>
2
  <package>
3
  <name>Antidot_Antidot</name>
4
+ <version>1.1.1</version>
5
  <stability>stable</stability>
6
  <license>LGPL</license>
7
  <channel>community</channel>
17
  Add cdata for variant name&amp;#xD;
18
  Add variant details for grouped products</notes>
19
  <authors><author><name>Antidot</name><user>antidot</user><email>contact@antidot.net</email></author><author><name>Antidot</name><user>antidot</user><email>contact@antidot.net</email></author></authors>
20
+ <date>2015-06-04</date>
21
+ <time>15:21:13</time>
22
+ <contents><target name="mage"><dir name="shell"><file name="antidotExport.php" hash="84b760a0cab3cc225ff8b50d6d25ed61"/><file name="antidotExportCategory.php" hash="87ebde88a80a1eb1f919aca67a69984b"/><file name="antidotExportInc.php" hash="437d19933543a58c8becd250613e5c26"/><file name="antidotExportProduct.php" hash="62c1fda71a6929d6e19864df9654c8a9"/></dir><dir name="i18n"><file name="de_DE" hash="f166a5ff29213a44fca77277b053897e"/><file name="en_US" hash="63c821044fda6f7c2a26dc84670b25bd"/><file name="es_ES" hash="f9319039054998955d63d51ed0930f3f"/><file name="fr_FR" hash="632367797f2fa9fef06e0b0c69377e01"/><file name="i18n.php" hash="0780b44563432f6e70de78f7a9d60f54"/></dir></target><target name="magecommunity"><dir name="MDN"><dir name="Antidot"><dir name="Block"><dir name="Catalog"><dir name="Layer"><dir name="Filter"><file name="Attribute.php" hash="2158b991ccdf394c8cd47cab00829e4d"/><file name="Boolean.php" hash="d17b08e1ec9047cf4050442ababd0808"/><file name="Category.php" hash="78cb53233ad74a2b5496d6f7857d8837"/><file name="Decimal.php" hash="75b31617bca2a8f20ee7fe113e3534f2"/><file name="Price.php" hash="244068a33e8ba64423c126baf883d2b5"/></dir><file name="View.php" hash="bbdd9bb31663415001ab3751c6737cde"/></dir></dir><dir name="Catalogsearch"><file name="Category.php" hash="e9605415ba85929115a443b1b4f00ab0"/><dir name="Layer"><dir name="Filter"><file name="Attribute.php" hash="2b274bf7d8f8dbd915bdf73f65e694fc"/></dir></dir><file name="Layer.php" hash="52a903855aa9cb7211eb0932d01368af"/><file name="Result.php" hash="0b1b34570bafd6a517bb854d3c8475cc"/></dir><dir name="Html"><file name="Select.php" hash="fc7fb19df1dd378d4e9e0860d2d47d07"/></dir><dir name="System"><dir name="Config"><dir name="Button"><file name="AfsStore.php" hash="4f00570d46d27d1cf89785e8db42a332"/><file name="PushArticles.php" hash="a0cae65b4aba9b539421c0a6d06fb406"/><file name="PushCategories.php" hash="50e4b74388e1c5a65249c71dfae69400"/><file name="PushProducts.php" hash="bac543e1b17f91a558adef5da3012e28"/><file name="RestoreTemplate.php" hash="ffbbb0a73ff1ede611262a6a4da1a188"/><file name="ShowXml.php" hash="417ba0c9c62d8070b63f90397887dcc0"/></dir><dir name="Form"><dir name="Field"><dir name="Array"><file name="Additional.php" hash="acbde0308213fa976f55934fb45aba60"/><file name="AdditionalFeed.php" hash="b4489921424513278869ece9bbcd09be"/><file name="ArticleAdditional.php" hash="38c62d610f585c460151841f7350348b"/><file name="ArticleIdentifier.php" hash="ec9479fd1ca087a1fe924795cc9ff5f6"/><file name="DefaultSort.php" hash="61dec4828212e7a145b6eeda5c476858"/><file name="Facet.php" hash="dab308e0ac79a89be8d72e487739031e"/><file name="Identifier.php" hash="294c5d3bda7dae5637eabfdfdb08afc7"/><file name="ProductAdditionalFacet.php" hash="208e01078409951327f1794e17e11e89"/><file name="ProductAdditionalField.php" hash="9c9f9c9c1c940963e1a24c039a392cc4"/><file name="ProductIdentifier.php" hash="d30809119cb35018697533075f7ee485"/><file name="Sort.php" hash="6ece671c902cf6f5db66652a2c51e79f"/></dir><file name="CategoryAttribute.php" hash="1ba0dd22410eb27d18ac77b51f78ac49"/><file name="ProductAttribute.php" hash="3acbdaee390ce50e18d0ede1d641255d"/></dir></dir><dir name="Html"><file name="Export.php" hash="7cb82e5f21c769e5b39efc0be7b76473"/><file name="ShowXml.php" hash="7b70f39937aa9d24336edde6bdbdf97c"/><file name="Version.php" hash="34c624c382f3061cf322cfed52c416ac"/></dir></dir></dir></dir><dir name="Helper"><file name="Antidot.php" hash="7bbd2866c65a847e1415badb1ef0d015"/><dir name="CatalogSearch"><file name="Data.php" hash="81cc908609e68035d5714488f913e688"/></dir><file name="Compress.php" hash="9c057cf9d594b07e6d36c1142b9ceae6"/><file name="Data.php" hash="7d1ea248e2663e4c6369e7e5632b214f"/><dir name="Enterprise"><dir name="Search"><file name="Data.php" hash="8bfe0146c64511f86cb796638b65112f"/></dir></dir><file name="LogExport.php" hash="6d6b262327bf1d920fc2b5b112edfef6"/><dir name="ManaFilters"><file name="Data.php" hash="e5dd65e6e52c03427aa68528cc1f140a"/></dir><file name="Url.php" hash="1d2ee02a8e135bfc4b866f5219f62acd"/><file name="XmlWriter.php" hash="77addcc2f245646c50c3da4bcee16774"/></dir><dir name="Model"><dir name="Catalog"><dir name="Layer"><dir name="Filter"><file name="Attribute.php" hash="3cd18414abccea60c5497931bc95e21e"/><file name="Boolean.php" hash="dd0414e0d96833bec6e32aac321c2763"/><file name="Category.php" hash="9224a05ffa914bfcaded1c6c52bd92f9"/><file name="Decimal.php" hash="b9b1e2cff1d0332fab77d101dca4c3d2"/><file name="Item.php" hash="f7cd6f73001c61046277a4807c37c73b"/><file name="Price.php" hash="7529be0313a19896993f92eeb9dfc8a9"/></dir></dir><file name="Layer.php" hash="706000dd944a45f30826eccba2942862"/></dir><dir name="Catalogsearch"><dir name="Layer"><dir name="Filter"><file name="Attribute.php" hash="a83d6761a949c8196cba33948a48c8bf"/></dir></dir><file name="Layer.php" hash="c79230234992d8e7fd23d547280c71e4"/><dir name="Resource"><file name="Attribute.php" hash="80d2a34d746f307109b6bf910b0f2958"/></dir></dir><dir name="Export"><file name="Abstract.php" hash="38d6d6dbb68872d0c46e26c61c38c30e"/><file name="Article.php" hash="91ea6e7acae1519413711abfc076ad0c"/><file name="Category.php" hash="a326b576f9a5f0f90cb5f57f3f155b26"/><file name="Product.php" hash="4163be5219a5ba37afad555047f921b1"/></dir><file name="Observer.php" hash="8d7d35c1362b1597a773a749377f9b28"/><dir name="Resource"><file name="Advanced.php" hash="f4810c1af8d5a15f7a424d7baf5fc777"/><dir name="Catalog"><dir name="Product"><file name="Collection.php" hash="144dd8688830992c9300d420ed203a23"/></dir></dir><dir name="Engine"><file name="Abstract.php" hash="6ad534401be39ac25229b11fea341804"/><file name="Antidot.php" hash="8b9b768bb91471260e927d33879b85c0"/></dir></dir><dir name="Search"><file name="Abstract.php" hash="fd71154b987b16f8d13bc3e10a3faeac"/><file name="Search.php" hash="aeef203f9a3794e9ae1e35a825f0eca3"/><file name="Suggest.php" hash="6caac0bb7683b1d330049ed0d606f36f"/></dir><dir name="System"><dir name="Config"><file name="ArticleAttribute.php" hash="f3a9596d45f275299f16530a56845c96"/><dir name="Backend"><file name="Engine.php" hash="68c93651655a77c74fd79d1de6d19be3"/></dir><file name="CategoryAttribute.php" hash="9f19b99e16c99b0e8052b1e31d2a6317"/><file name="Dir.php" hash="c80d83280ebc5ab91fd45d246ec47ba3"/><file name="DisableEnable.php" hash="6d08f33a1580b2fd1d58d87248104166"/><file name="Engine.php" hash="a3703b427ee777ce4ea58c8b31604158"/><file name="Facet.php" hash="d5545b6ae7d9a69dfe4c49a1df48853e"/><file name="Number.php" hash="7985ea6c495a35173d68291389319f93"/><file name="Options.php" hash="06930da994dec4bb05ebc3f3e8c8abb8"/><file name="ProductAttribute.php" hash="c74ad00177c3a12b03c8684928d12c40"/><file name="PromoteRedirect.php" hash="c167973ea7a0ef09f0e5fa0fd0a08926"/><file name="Sort.php" hash="e0d2c1e72f56894b75baebcb6c4b8609"/><dir name="Suggest"><file name="Type.php" hash="cef491efdb9fcef86d0df75030206a78"/></dir><file name="WSStatus.php" hash="ff4954e15d75dd3139290d96773d0abf"/></dir></dir><dir name="Transport"><file name="Abstract.php" hash="3272c44b08523a9836aa15c835e2ed25"/><file name="File.php" hash="0941fd452279605a2ea6a5d40f857000"/><file name="Ftp.php" hash="8d1aa862bb8f3656bd199d5ce592e0b1"/><file name="Http.php" hash="fb80d47a6d991b9f706418061a2cbd7e"/><file name="Interface.php" hash="32d1d3958e0cd726bc34cae482464ef8"/></dir><file name="Transport.php" hash="de133bf273352bcafead75745fb347ba"/></dir><dir name="Test"><dir name="Block"><dir name="System"><dir name="Config"><dir name="Button"><file name="AfsStore.php" hash="dcbfefb440b8512b1298b624a3582076"/></dir></dir></dir></dir><dir name="Helper"><dir name="CatalogSearch"><file name="Data.php" hash="a40c1e58b5000432763aa07dd49d4b5d"/></dir><dir name="Data"><dir name="providers"><file name="testTranslateFacetlabel.yaml" hash="23213ce3f459d4df8ddf1f9440258ad7"/></dir></dir><file name="Data.php" hash="4372c47518dbbfc5998229315c728bfe"/></dir><dir name="Model"><dir name="Export"><file name="Article.php" hash="c2d43ccf7c9b6648b633d122c657f27d"/><file name="Category.php" hash="c29dbe5ffb63eae4d51e57f7ff298bd3"/><dir name="Product"><dir name="fixtures"><file name="testWriteImageUrl.yaml" hash="a4e08b8f1565eba67a16553cf57e1004"/><file name="testWritePricesFixedtax.yaml" hash="a4e08b8f1565eba67a16553cf57e1004"/><file name="testWriteProductNoVariant.yaml" hash="626a27b35977e5a52b02f85011c5e216"/><file name="testWriteProductUrl.yaml" hash="a4e08b8f1565eba67a16553cf57e1004"/><file name="testWriteProperties.yaml" hash="d434749b80908bbceefd5781e2d0e998"/><file name="testWriteXml.yaml" hash="c53ef98d6dea648dc63cc34ce3ee9509"/></dir><dir name="providers"><file name="testWriteImageUrl.yaml" hash="666c33585c611bcc0b0ebe6e87dce1fc"/><file name="testWriteProductUrl.yaml" hash="18f511460efea04586fc888f5c85b3ea"/></dir></dir><file name="Product.php" hash="9dc6adb78d5d9fb1d9b43b39a9766208"/></dir><dir name="Observer"><dir name="fixtures"><file name="testGetDefaultContext.yaml" hash="e9c8aa4acd4e2c3af2e69c8eb04996bc"/></dir><dir name="providers"><file name="testGetOwnerForFilename.yaml" hash="c5c07e73f536f9ffacc0c3ff6b5a13d1"/></dir></dir><file name="Observer.php" hash="86536c523b1249b9d100a5dc40ea7793"/><dir name="Resource"><dir name="Engine"><file name="Antidot.php" hash="7e59165d905a8679fe282a9dd8d0e285"/></dir></dir><dir name="Search"><dir name="Suggest"><dir name="fixtures"><file name="testSuggest.yaml" hash="e832d29df357927ddb3896422985a037"/></dir></dir><file name="Suggest.php" hash="d97172c8ec094146f953a9704f8e1936"/></dir><dir name="System"><dir name="Config"><dir name="Sort"><dir name="expectations"><file name="testToOptionArray.yaml" hash="13fc5b4c17962fb267f443d03a2219b2"/></dir><dir name="fixtures"><file name="testToOptionArray1.yaml" hash="f1e09ff12a4c13817d3aafd9254d3f7c"/><file name="testToOptionArray2.yaml" hash="160c861aa7adf28b4d3dc1423dcc8d84"/><file name="testToOptionArray3.yaml" hash="bbb2d78972449929cac497c62ec6fef8"/></dir></dir><file name="Sort.php" hash="8173c08ae65d529ace25a745ffd4b3e6"/></dir></dir></dir><file name="PHPUnitUtil.php" hash="2a128a7c19f4c37cb9dd7fc60e679693"/></dir><dir name="controllers"><dir name="Admin"><file name="PushController.php" hash="fb131afc3d26e5e591968e8fa3ed5375"/></dir><dir name="Front"><file name="SearchController.php" hash="d220bd4628830ea238775ed9788e0674"/></dir></dir><dir name="etc"><file name="config.xml" hash="f3faf993d73c5f65f5a0878cb0b7dc42"/><file name="system.xml" hash="f6e7ac229fe171ef4896ea9c97643aef"/></dir><dir name="sql"><dir name="Antidot_setup"><file name="mysql4-install-0.9.php" hash="62672bc47ea92dbd46966fb76e4251e0"/></dir></dir></dir></dir></target><target name="magedesign"><dir name="frontend"><dir name="base"><dir name="default"><dir name="template"><dir name="antidot"><dir name="catalog"><dir name="layer"><file name="category.phtml" hash="3ec81f7b3e3b947317da8664c8e15927"/><file name="filter.phtml" hash="2304baebff9b798e0ebd977fbc891346"/></dir></dir><dir name="catalogsearch"><file name="result.phtml" hash="12c082ddff0e6c4fef74630b8253face"/></dir></dir></dir></dir></dir><dir name="default"><dir name="default"><dir name="layout"><file name="antidot.xml" hash="654b0cbb9d7c3f7a0a506e3f6adf164b"/></dir><dir name="template"><dir name="antidot"><dir name="catalogsearch"><dir name="result"><file name="category.phtml" hash="7413580b825508f2cfc08566d62369ae"/></dir></dir></dir></dir></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="MDN_Antidot.xml" hash="988c6b7e9da4e50f1727956833ab1696"/></dir></target><target name="magelocale"><dir name="de_AT"><file name="MDN_Antidot.csv" hash="e8934b63a9f0d668f07ae95287637e28"/></dir><dir name="de_CH"><file name="MDN_Antidot.csv" hash="e8934b63a9f0d668f07ae95287637e28"/></dir><dir name="de_DE"><file name="MDN_Antidot.csv" hash="e8934b63a9f0d668f07ae95287637e28"/></dir><dir name="es_AR"><file name="MDN_Antidot.csv" hash="7a6a749b1da8b3fca7823e8b08f53add"/></dir><dir name="es_CL"><file name="MDN_Antidot.csv" hash="7a6a749b1da8b3fca7823e8b08f53add"/></dir><dir name="es_CO"><file name="MDN_Antidot.csv" hash="7a6a749b1da8b3fca7823e8b08f53add"/></dir><dir name="es_CR"><file name="MDN_Antidot.csv" hash="7a6a749b1da8b3fca7823e8b08f53add"/></dir><dir name="es_ES"><file name="MDN_Antidot.csv" hash="7a6a749b1da8b3fca7823e8b08f53add"/></dir><dir name="es_MX"><file name="MDN_Antidot.csv" hash="7a6a749b1da8b3fca7823e8b08f53add"/></dir><dir name="es_PA"><file name="MDN_Antidot.csv" hash="7a6a749b1da8b3fca7823e8b08f53add"/></dir><dir name="es_PE"><file name="MDN_Antidot.csv" hash="7a6a749b1da8b3fca7823e8b08f53add"/></dir><dir name="es_VE"><file name="MDN_Antidot.csv" hash="7a6a749b1da8b3fca7823e8b08f53add"/></dir><dir name="fr_CA"><file name="MDN_Antidot.csv" hash="5a408d02979b224a1387c1be415caa37"/></dir><dir name="fr_FR"><file name="MDN_Antidot.csv" hash="aed12e90a30b556952e5c33dd904867a"/></dir></target><target name="mageweb"><dir name="js"><dir name="mdn"><dir name="antidot"><file name="CollapsibleLists.js" hash="86792ecde0c2759ba85e0d863dd147ce"/></dir></dir></dir></target><target name="magelib"><dir name="antidot"><dir name="AFS"><dir name="ACP"><file name="Makefile" hash="0f76232bfabc275a3dac973666fb5dae"/><dir name="TEST"><file name="Makefile" hash="ce56cc786e1df50148e1d3222c05e5f8"/><file name="acpConnectorTest.php" hash="25a8194f3dc8895640df4f4bba895d8e"/><file name="acpQueryTest.php" hash="74ad65a4af639a409ee72a75a2a043d6"/><file name="acpReplysetHelperTest.php" hash="4f0a0d471a06e139cd11c715b67ebe81"/><file name="acpResponseHelperTest.php" hash="6d30f99108db0d9956aef9ba5e1d88df"/><file name="acpTest.php" hash="d6119d150543e7943ba4e9907901ae5d"/></dir><file name="afs_acp.php" hash="78dbfbc92f68469c92898f1da4263e68"/><file name="afs_acp_configuration.php" hash="2d644cc6c5bf2cdaeca5780576c4bf0e"/><file name="afs_acp_connector.php" hash="b72439562b02024e0b9629c18394985d"/><file name="afs_acp_exception.php" hash="f610d2cc37a15d4b981d7b43939414ad"/><file name="afs_acp_query.php" hash="ced0629355f5d4fc1c219d1adb03297d"/><file name="afs_acp_query_manager.php" hash="b3348972a850c904fc664b4e27671439"/><file name="afs_acp_reply_helper.php" hash="b0259f24f10d2e92ed6e3b8cdaaacc44"/><file name="afs_acp_replyset_helper.php" hash="07e7fdb88a42a399c96261c47ffb0231"/><file name="afs_acp_response_helper.php" hash="33a66106fd3a94194514a0d8d39af1cd"/></dir><file name="Makefile" hash="7bb31592939024f74745d6b6cb7fec0b"/><dir name="SEARCH"><dir name="FILTER"><file name="Makefile" hash="d42338199c6857ded179af2117b9f571"/><dir name="TEST"><file name="Makefile" hash="ab37090c6c5e7af1b260376237737700"/><file name="filterBuilderTest.php" hash="161ff5c8e73914eef884d17456afa133"/><file name="filterCombinationTest.php" hash="2162288d5255d3b24fe94d75b939aa51"/><file name="filterTest.php" hash="1682c0a4d50158a8d2c9369d30e45a18"/><file name="groupFilterTest.php" hash="1ebe8ce7344ed64b93cf94632d3b0184"/></dir><file name="afs_combinable_filter.php" hash="336e6c6bc9ebae3f58602d23ef734182"/><file name="afs_combinator_filter.php" hash="e2fc560b9c0c31f20c73f2057a8b7b69"/><file name="afs_filter.php" hash="6dbfc8c668cd48510cc9a9243d1bf4c3"/><file name="afs_filter_exception.php" hash="ccce583c63a4a65f7f0a27fc4a487505"/><file name="afs_filter_wrapper.php" hash="30dec104456abc037019ad93922b5afd"/><file name="afs_group_filter.php" hash="b95fa3bc0e26bc39dfc53a6010bce32f"/><file name="afs_native_function_filter.php" hash="37176bdbc66cc3dca18149132921f0a5"/><file name="afs_operator_filter.php" hash="c7ea43c8d64eedbe33397f61737e0226"/><file name="afs_valued_filter.php" hash="483653071734f77972c9b9771e187d82"/></dir><file name="Makefile" hash="0f76232bfabc275a3dac973666fb5dae"/><dir name="TEST"><file name="Makefile" hash="ce56cc786e1df50148e1d3222c05e5f8"/><file name="clientDataHelperTest.php" hash="1556ab047e1df23447586d529768befd"/><file name="clusterHelperTest.php" hash="e112e7c756f63c8e8ceb554281b418c9"/><file name="conceptHelperTest.php" hash="b44e39b62d0537bf1f7b7feb23f8111f"/><file name="facetDefaultTest.php" hash="382e4ea35e1c7173371b4a84046a38e5"/><file name="facetHelperTest.php" hash="d51a714bc116e77f5f115c26e9640f10"/><file name="facetManagerTest.php" hash="bbef8e207c387dbe6a26142fd55264d5"/><file name="facetTest.php" hash="26123aa75cb2597a3ededfa9d778095d"/><file name="facetValuesSortOrderTest.php" hash="b650080bf9b2cce2ac42a245cb84c911"/><file name="feedCoderTest.php" hash="f2b5dfdd4fa3c4e5d14c790d15235146"/><file name="filterCoderTest.php" hash="46249fa13edccf1e5d5000daf2573b77"/><file name="headerHelperTest.php" hash="8eb9450972ce082c35d7b66be7735d79"/><file name="helperConfigurationTest.php" hash="be3f74e53e27744e8214f3c341172796"/><file name="intervalTest.php" hash="912389dad049853f6bf0b4eab2af5034"/><file name="metaHelperTest.php" hash="080f160b54636c4eee743544a6a12bee"/><file name="pagerHelperTest.php" hash="d96a9891523e453647493f3219e86357"/><file name="promoteBannerReplyHelper.php" hash="94c3c14517536437e9800eaa706fbe29"/><file name="promoteRedirectReplyHelper.php" hash="ed00c66be5127d8b374f6416abf328ef"/><file name="promoteReplyHelperTest.php" hash="7cbb68a7f50c2bd2ef11a085ac94deb2"/><file name="promoteReplysetHelperTest.php" hash="ac2f1e3073015143dc7b2b705711c845"/><file name="queryCoderTest.php" hash="03983a114c6697464f8bf016822ff4a3"/><file name="queryTest.php" hash="338264d8e6dbbc09e88bd9a8179e8be4"/><file name="replyHelperTest.php" hash="4d86f19ea7de2aece5d7fd9c143c3dbc"/><file name="replysetHelperTest.php" hash="897f074b8382c6853f51b06a5ee50b0a"/><file name="responseHelperTest.php" hash="ebb167e1c330af6aa0e6a2b917431040"/><file name="searchConnectorTest.php" hash="9201de573884b643041b6c32bc535e7e"/><file name="searchQueryManagerTest.php" hash="2188b262a1c11422bcc8133f68fa6dd9"/><file name="searchTest.php" hash="fa47a7819b5c7c71172d6b1f1e7a02f7"/><file name="spellcheckHelperTest.php" hash="49960fb90055dcf265ef41e491c11325"/><file name="spellcheckTextVisitorTest.php" hash="203f0d08f548a39135517a41f6e9e43a"/><file name="textVisitorTest.php" hash="b722845dd0f5f953574cb51284ad025b"/></dir><file name="afs_base_reply_helper.php" hash="57abe4828b7ed7126db963764faa718a"/><file name="afs_base_replyset_helper.php" hash="096b124a3ebdc6e8d6beb359bd8bb7c5"/><file name="afs_client_data_exception.php" hash="899957af974d04aa7eaca44903a7f86c"/><file name="afs_client_data_helper.php" hash="4700218e2400350014fde428bc86806b"/><file name="afs_cluster_exception.php" hash="86d97623db7aebaa28a20857ce2cf17f"/><file name="afs_cluster_helper.php" hash="60b7fbcc869a672929ef9fc6d840d2b2"/><file name="afs_cluster_parameter.php" hash="20ed527d3ed1a6cf2bc80e032ecd2c7e"/><file name="afs_coder_base.php" hash="fb87fbea43d12695154b3b6102e2a019"/><file name="afs_coder_interface.php" hash="3b179b2513e215751ee4edd190b2a719"/><file name="afs_concept_helper.php" hash="982cf3d2063c565cf19cc6136b049066"/><file name="afs_count.php" hash="9f83f3baa3cf4462c0db786f4eea479a"/><file name="afs_facet.php" hash="1b4d7d35ebe8ed4894fda4881d0b168f"/><file name="afs_facet_combination.php" hash="005e9742ee032194b86856195dd59f7d"/><file name="afs_facet_default.php" hash="cbcb5d28b7b00815ce5248017065e84b"/><file name="afs_facet_exception.php" hash="f1f0afdbf9a727b53c4731e5a40ac417"/><file name="afs_facet_helper.php" hash="fe1ca1e7242c319bac96488b1f5e2063"/><file name="afs_facet_helper_retriever.php" hash="5628cc41c50ab25fd3336df302d903f4"/><file name="afs_facet_layout.php" hash="c83f6fef1c13ba3cda667c611841ff87"/><file name="afs_facet_manager.php" hash="a3fabb34d56a9614d4a0a2917f6fea0c"/><file name="afs_facet_mode.php" hash="8dcac389a37f8267a367400377631dba"/><file name="afs_facet_sort.php" hash="0d7ba4059b10da9981b9c801355cb874"/><file name="afs_facet_type.php" hash="6df82cbfa627629f9523437994d1fbb1"/><file name="afs_facet_value_formatter.php" hash="d6580281f9ef5c0820615ac385aae863"/><file name="afs_facet_values_sort_mode.php" hash="17def98365132c810515f8cf3c6fb006"/><file name="afs_facet_values_sort_order.php" hash="f95f77cb5dd7015e4f2e6094ddba49a6"/><file name="afs_feed_coder.php" hash="ed7b40e872a7ed5aa30adbcffc05de56"/><file name="afs_filter_coder.php" hash="4edbdcf6760d80465e5d2533014ba307"/><file name="afs_filter_parameter.php" hash="2b03c2c83ffe2e2968aaf50ad4903921"/><file name="afs_fts_mode.php" hash="edbd9342cd9625183e1e01ed81b79fc3"/><file name="afs_header_helper.php" hash="3b30d839efe9128773c82d47cbd591b8"/><file name="afs_helper_configuration.php" hash="dbd0378574fbc5729babfbddfef0fd67"/><file name="afs_interval.php" hash="dbf9749881be0a2b063f8a33dff214f3"/><file name="afs_interval_exception.php" hash="40f223de231df03aae59596c1a493065"/><file name="afs_meta_helper.php" hash="8403689868c98db725ebd11748508c8b"/><file name="afs_pager_helper.php" hash="077052931e0cffb1e589c21b57156b38"/><file name="afs_producer.php" hash="7c8c515ccb8126523fa0d09a7f759dd5"/><file name="afs_promote_banner_reply_helper.php" hash="418702b3c053029b3aa8fcb2775c65bd"/><file name="afs_promote_redirect_reply_helper.php" hash="be17eda6f8b4552b9ec21183362171a2"/><file name="afs_promote_reply_helper.php" hash="0e2a4f67cd307f74e8b64cd3b158235c"/><file name="afs_promote_replyset_helper.php" hash="fdefc6f8a686addb31ea9b6c0a3fa5ad"/><file name="afs_query.php" hash="bd969a62cd4bbbcb5b9996eaa19353f7"/><file name="afs_query_coder.php" hash="ca0bfad66b8d8549ab3f33380d716732"/><file name="afs_query_coder_interface.php" hash="dd16f17b3606a7418c1c714475b19b51"/><file name="afs_query_object_interface.php" hash="a9af13e2c856e4136ccadfff60f72d36"/><file name="afs_raw_text_visitor.php" hash="fd574583c4c9110165c1cadc67b832de"/><file name="afs_reply_helper.php" hash="3919f9e83cba62be9bc67117b1087b03"/><file name="afs_reply_helper_factory.php" hash="f159f7d0ef7e5a209fb872a970d0d582"/><file name="afs_replyset_helper.php" hash="cb8f81391d9a59904dcb0c3d6ae31999"/><file name="afs_response_exception.php" hash="0a865bb92fb700ae555dcb5ae675f644"/><file name="afs_response_helper.php" hash="2fec8d101712087660dc6aba5119e3c2"/><file name="afs_search.php" hash="3f2e3ef447515a2fa05b270654ef2969"/><file name="afs_search_connector.php" hash="17242fb6536f4596b2c0198a16986310"/><file name="afs_search_query_manager.php" hash="77e30683ee4ba9e004e9c7c12d9c811d"/><file name="afs_sort_builtins.php" hash="0cc1617a62f1a834a28d7d2ac249b081"/><file name="afs_sort_coder.php" hash="1dfe2d32278383d8465df67535cb91dd"/><file name="afs_sort_order.php" hash="7755deb99386650c9974871474168cda"/><file name="afs_sort_parameter.php" hash="bfb8c59c1560ec8a3b597dc45aa8ecd5"/><file name="afs_spellcheck_helper.php" hash="bb5465848ada7a9df9875f2565fb9686"/><file name="afs_spellcheck_text_helper.php" hash="3ca5c3118660aa600aadb504ceff6c4c"/><file name="afs_spellcheck_text_visitor.php" hash="c44c23ae21f61b065e457911bbc45ed2"/><file name="afs_text_helper.php" hash="59c4ae24560948c3af0f4adbf6bd1803"/><file name="afs_text_visitor.php" hash="867b44a280403cd4567358ec6d59588a"/></dir><file name="afs_configuration_base.php" hash="f26dd9efda4923cc2c71057f21be97d9"/><file name="afs_connector.php" hash="aa04a21163b57ef338bf96bd55e95882"/><file name="afs_exception.php" hash="c1840fe279f9cb313cec151012ed4513"/><file name="afs_feed.php" hash="005305cace79a3aa7719a3c942df9da7"/><file name="afs_multiple_values_parameter.php" hash="96dc30f1fbf137cbfd73c2b195d9f9ef"/><file name="afs_origin.php" hash="a6b7e39a687210572c116afcbea0e7cb"/><file name="afs_query_base.php" hash="7209115a714d9b7de209a0af691c1d22"/><file name="afs_query_parameter.php" hash="6552428d955d0a48c015e1f98ba62815"/><file name="afs_response_helper_base.php" hash="b087f7bdad35ed0526566042ef9afc8c"/><file name="afs_single_value_parameter.php" hash="65d002d7ac6b6e8dd6170309b4c84649"/></dir><dir name="AIF"><file name="Makefile" hash="2d232abf9913fcabb44033d5e5d1ebfd"/><dir name="TEST"><file name="Makefile" hash="24d3030d27e88732028d14fb1d81c203"/><file name="afsMultipartResponseTest.php" hash="70a64d0d599ea01806fac2126fb3680a"/><file name="authenticationTest.php" hash="2e476e9ab15ee221ddd63bb555262a28"/><file name="bowsInformationTest.php" hash="3bbfe71f431a35f0285afdca40906874"/><file name="documentManagerTest.php" hash="ad90a6146f5aeee383355bb05425b3dd"/><file name="documentTest.php" hash="59b204b10b90cd764b259ad4c2bc043a"/><file name="pafConnectorTest.php" hash="ac2928b501d9ea167af43dbf3adafa7d"/><file name="pafLiveTest.php" hash="92862c31d151c34b2caf44bff9d0fb80"/></dir><file name="afs_about_connector.php" hash="8972264a9b7cce237ad1a4b47852b529"/><file name="afs_authentication.php" hash="4285035550c9681a047b85abbca64936"/><file name="afs_bows_connector.php" hash="47a6bcafd5eba2361d2cea409f60d3f7"/><file name="afs_bows_connector_interface.php" hash="8fdf9749f0500a39741d696feb55af14"/><file name="afs_bows_exception.php" hash="1bd8657a37b8b4a9e08bfc4eb6b7e416"/><file name="afs_bows_information.php" hash="1f96a4cd84b2332f1186f9e0cea8542d"/><file name="afs_bows_information_cache.php" hash="1ae9a9243342c4e58a52e70473b68472"/><file name="afs_document.php" hash="c0003ec962a79b9d3f642b17bade0fff"/><file name="afs_document_manager.php" hash="8c5c0105d9337b7ae6a9f041f643ea88"/><file name="afs_multipart_response.php" hash="f2077c9eaf121fabdb2fc26c23b2e256"/><file name="afs_paf_connector.php" hash="96111b0536c83874b7c06ada5577106b"/><file name="afs_paf_live_connector.php" hash="9efeb2716f6d95e666f9c37726869fe7"/><file name="afs_paf_upload_reply.php" hash="0cb4905d1c894637d5e6acbd2cffc112"/><file name="afs_token_authentication.php" hash="1f003310f156f0a71db1d273375172d8"/><file name="afs_user_authentication.php" hash="03deeead93ee32753f2f7f80cfc011f4"/></dir><dir name="COMMON"><file name="Makefile" hash="7bb31592939024f74745d6b6cb7fec0b"/><dir name="TEST"><file name="Makefile" hash="d568cfe3683543f363312aa4b6d2bbad"/><file name="languageTest.php" hash="ad0f75b1c2f320c81eba32cade86191c"/><file name="toolsTest.php" hash="9276cb1a275d697f8e8365f2ac340cdf"/><file name="userSessionManagerTest.php" hash="b2b78d6fa156f1a61065f8ee5bfc6e0b"/></dir><file name="afs_connector_base.php" hash="b6b1f091ec71e5b92e4a1e5ca958255f"/><file name="afs_connector_interface.php" hash="68ad5e20a861b85dbf198f79cd2afd4c"/><file name="afs_exception.php" hash="b8eed4376088ae3003d0b77cc523e732"/><file name="afs_helper_base.php" hash="839cca78a663c3a22b4a8e35d1460129"/><file name="afs_helper_format.php" hash="30a3f6e945db7412ef95e83e7b0b5898"/><file name="afs_language.php" hash="277acb15b86089b37c812c47f2141d3c"/><file name="afs_service.php" hash="12c00c906e130860120552c40fa9dbc2"/><file name="afs_service_status.php" hash="1dee172850a76b46987534df89013878"/><file name="afs_tools.php" hash="26f6c01c5a61987925385e7a35260399"/><file name="afs_user_session_manager.php" hash="abd625f6b7b5cecf386dac9d82887764"/><file name="afs_versions.php" hash="556c912ff7f19f5083c4fb44d4d40ac6"/><dir name="lib"><dir name="JsonPath"><file name="JsonPath.php" hash="baa12e1baa9f8a20a095463042e96ad3"/><file name="JsonStore.php" hash="a9632aeb2126e98db9a49403a8f2ff77"/></dir></dir><dir name="php-SAI"><file name="README.md" hash="63ab581c83fe44918e6d074e20f08f95"/><dir name="lib"><dir name="Curl"><file name="Handle.php" hash="0fc7132737da7cee7df6b974447864ac"/></dir><file name="Curl.php" hash="358e4d3afca2035ee4d3f99f372ed15a"/><file name="CurlInterface.php" hash="714fa045dd4546d0c92cd022efb09422"/><file name="CurlStub.php" hash="fbdc0ece6321c5b5a1e27a65449f4a1f"/><dir name="rb_temp"><file name="HttpClient.php" hash="091b91c98acf9f1cd6c3d6d75cddfb88"/><file name="MultiCurl.php" hash="916e85d73bae6e136f889166ebc6db17"/><file name="SimpleCurl.php" hash="c296966a8bda96e03b464a1d3a9c8e06"/></dir></dir><dir name="tests"><file name="SAI_CurlStubTest.php" hash="bce69cbb17a40bd4eeba6bad1133216e"/></dir><file name=".gitignore" hash="09e625dea07b4d4098b19ec998d266f9"/></dir></dir><file name="COPYING" hash="b234ee4d69f5fce4486a80fdaf4a4263"/><file name="COPYING.LESSER" hash="4fbd65380cdd255951079008b364516c"/><file name="FAQ.md" hash="7d7c886674d70a0047303c5d93de6165"/><file name="Makefile" hash="225475a5a4a0204cecbb77621ff38bb2"/><file name="README.md" hash="7ecfd33825a0e6bc50cca099c1c0e50e"/><file name="afs_lib.doxygen" hash="8128d53d894cc57e08142377d13c72f4"/><file name="afs_lib.php" hash="946834742cd313e818f79bb96b6dfb52"/><file name="afs_version.php" hash="d2d295f9758c29cb26173f9095ff1400"/><file name="composer.json" hash="39190df70fafa99d7eb5ab566e8edf3f"/><dir name="doc"><file name="afs_filter_documentation.dox" hash="3bf4b96e25d95ce5953b822038c6f135"/><file name="afs_paf_upload.dox" hash="d36893db0234f171e6cfb43f6e13d47c"/><file name="afs_search.dox" hash="b1c5ab8728703822f910852cd17561f4"/><file name="afs_search_coder.dox" hash="77709e1bc691301017f0982e0348a9b9"/><file name="afs_search_query.dox" hash="21dcd1734a165a4cb3b4f62c42a6a0be"/><file name="afs_search_reply.dox" hash="cdb1d42447671f4352927b40b3f8f37d"/><dir name="data"><file name="acp_helper_example.php" hash="2815890e7afbae78e7eb4e6fc5c88f6f"/><file name="full_example.php" hash="e152a964d06e55de460c596070c714d8"/><file name="full_lightweight_example.php" hash="eac3bb2d251052f547a9f737e5cd0461"/><file name="raw_example.php" hash="703356b9284e7fe904cf1334abbe08c9"/><dir name="templates"><file name="error_template.html" hash="70f44bd0f45470d379a11d0a2fe507e4"/><file name="facet_template.html" hash="6836005a7dae45e9415273f1eb6b78e2"/><file name="facet_values_template.html" hash="9b41f2b55a1cecae5724b4fcd4a46cfb"/><file name="meta_template.html" hash="e664a3bb222d272ce2451fb10bf46de4"/><file name="pager_template.html" hash="2700ab5b60a1f9553b1c39374fda63d4"/><file name="result_template.html" hash="1572a4ef4e8dda0b3db1ea77bbed4a98"/><file name="spellcheck_template.html" hash="8042054a1f5a271b47c77f81436c4791"/></dir></dir><file name="detailled_integration_example_with_template.dox" hash="26ef377a6ef546b636a0e254d11d01f5"/><file name="lightweight_integration_example_with_template.dox" hash="5a388d2dbfad63ad6ec353407b79a6bb"/><file name="logo-antidot-long-200x41.png" hash="1ceac3fff767fb5e395bd767344a3d13"/><file name="main.dox" hash="ca3e97f95deead927fb3298ecafbad5e"/><file name="raw_integration_example.dox" hash="56a7126d008c2e49abdf9bf0b5ec9717"/><file name="template_prerequisites.dox" hash="baa24a943e19ff3654227850bd316abb"/><file name="templates_in_details.dox" hash="5e8db94382f1fbd6c4e0b424a9edc9a3"/></dir><file name="rules.mk" hash="ff48aa6a5c40e31b3f38aba1267e9a71"/><dir name="scripts"><file name="gen_doc.sh" hash="0f6fc60aca94da563397d3c710bd9d33"/><file name="increment_version.sh" hash="431db9c60d2f94d251be07957787fcb0"/><file name="print_version.sh" hash="a05ddc19cd27ff185721fe2bd0cffc25"/><file name="version_management.sh" hash="3d5ecd39f45ba081144b3033dbd14330"/></dir><file name=".gitignore" hash="0292f51c0906b2092255872c69603f29"/><file name=".travis.yml" hash="4330b9c449e9cd0e97829f679c2a2786"/></dir></target><target name="mageskin"><dir name="frontend"><dir name="base"><dir name="default"><dir name="css"><dir name="mdn"><dir name="antidot"><file name="CollapsibleLists.css" hash="c956d83facc41a97bf14726dcb953edb"/></dir></dir></dir><dir name="images"><dir name="mdn"><dir name="antidot"><file name="base.gif" hash="1f71b021e061a4948d69adc4ff10ccad"/><file name="button-closed.png" hash="563b78324e0712c0902cb4f77cb9eb86"/><file name="button-open.png" hash="c710849a0d2b61ad1f0fc36c0e59d131"/><file name="button.png" hash="97f3055c5046c851eea2dad7e5227508"/><file name="cd.gif" hash="f41037663522fab5c5c31530c7fa43d8"/><file name="empty.gif" hash="df22aff6e941ff1cc577333d1712b584"/><file name="folder.gif" hash="ea16980ab437fa6ba4aba3d480e83e9e"/><file name="folderopen.gif" hash="18aa3d75315bf95bf080357733437fcc"/><file name="globe.gif" hash="d6b48614cf8dc9553e077c19197637d2"/><file name="imgfolder.gif" hash="1d488d377762e65ab4e8b691ba01e5a4"/><file name="join.gif" hash="4d5d614e0da056df815a4306d6368692"/><file name="joinbottom.gif" hash="4b3daa7f2cc584f1aac0d142275d7cba"/><file name="line.gif" hash="63ab38a6203262f15ca46c631232ea2c"/><file name="list-item-contents.png" hash="00ae24d5bc76df9eedaea597859963e4"/><file name="list-item-last-open.png" hash="615ddd71f81b240e9ed7d4e383b2c01a"/><file name="list-item-last.png" hash="e2bfb790f46855c378e50f3c0a82ea01"/><file name="list-item-open.png" hash="732d1cc59f3a488c89c624eb434eac98"/><file name="list-item-root.png" hash="5529d21e7ec68e9cb750a4895ff0b480"/><file name="list-item.png" hash="e03ec1bf3d9e16bb3005ccf8d26eaa6c"/><file name="minus.gif" hash="d647fbbd0ec410b8f3bb3357b62eedcf"/><file name="minusbottom.gif" hash="b09d684cca7135ef728141aaf2464baa"/><file name="musicfolder.gif" hash="21ece951734f23adb2f75befe1f31fc1"/><file name="nolines_minus.gif" hash="eb2243a354ffcfac93ba0fe948f7167d"/><file name="nolines_plus.gif" hash="ec92b634b63608fb4b0dbf114e3b89e1"/><file name="page.gif" hash="c25b136c1cb3bb145495c25b35d93754"/><file name="plus.gif" hash="5c55d798909c553deca31d610bd18fac"/><file name="plusbottom.gif" hash="1924ce363c38a992f888a4df48c0b274"/><file name="question.gif" hash="ea0ca196ce0ebfd625cc1210abfdec6c"/><file name="trash.gif" hash="6cbfd3ed29531044aed9b4edb3cca9ad"/></dir></dir></dir></dir></dir></dir></target></contents>
23
  <compatible/>
24
  <dependencies><required><php><min>5.2.0</min><max>5.6.0</max></php><extension><name>curl</name><min/><max/></extension></required></dependencies>
25
  </package>