Flagbit_Factfinder - Version 3.3.6

Version Notes

bugfix: dont fail if products campaigns cant be loaded.
bugfix: dont use product campaigns, if campaigns are disabled.
task: show ff search form only if suggest is enabled
task: apply cluster level into attribute objects
task: flush output buffer for each bulk on product export

Download this release

Release Info

Developer Magento Core Team
Extension Flagbit_Factfinder
Version 3.3.6
Comparing to
See all releases


Version 3.3.6

Files changed (137) hide show
  1. app/code/community/Flagbit/FactFinder/Block/Adminhtml/Cockpit.php +33 -0
  2. app/code/community/Flagbit/FactFinder/Block/Adminhtml/Form/Field/Attribute.php +54 -0
  3. app/code/community/Flagbit/FactFinder/Block/Adminhtml/Form/Field/Attributes.php +85 -0
  4. app/code/community/Flagbit/FactFinder/Block/Campaign/Advisory.php +23 -0
  5. app/code/community/Flagbit/FactFinder/Block/Campaign/Cart/Advisory.php +56 -0
  6. app/code/community/Flagbit/FactFinder/Block/Campaign/Cart/Feedback.php +53 -0
  7. app/code/community/Flagbit/FactFinder/Block/Campaign/Feedback.php +62 -0
  8. app/code/community/Flagbit/FactFinder/Block/Campaign/Product/Advisory.php +42 -0
  9. app/code/community/Flagbit/FactFinder/Block/Campaign/Product/Feedback.php +42 -0
  10. app/code/community/Flagbit/FactFinder/Block/Cart/Crosssell.php +93 -0
  11. app/code/community/Flagbit/FactFinder/Block/Filter/Slider.php +36 -0
  12. app/code/community/Flagbit/FactFinder/Block/Layer.php +127 -0
  13. app/code/community/Flagbit/FactFinder/Block/Layer/Abstract.php +33 -0
  14. app/code/community/Flagbit/FactFinder/Block/Product/List/Crosssell.php +63 -0
  15. app/code/community/Flagbit/FactFinder/Block/Product/List/Upsell.php +115 -0
  16. app/code/community/Flagbit/FactFinder/Block/Scic.php +89 -0
  17. app/code/community/Flagbit/FactFinder/Block/TagCloud.php +44 -0
  18. app/code/community/Flagbit/FactFinder/Block/XmlConnect/Catalog/Product/List.php +124 -0
  19. app/code/community/Flagbit/FactFinder/Block/XmlConnect/Catalog/Search.php +123 -0
  20. app/code/community/Flagbit/FactFinder/Block/XmlConnect/Catalog/Search/Suggest.php +56 -0
  21. app/code/community/Flagbit/FactFinder/Helper/Backend.php +228 -0
  22. app/code/community/Flagbit/FactFinder/Helper/Data.php +36 -0
  23. app/code/community/Flagbit/FactFinder/Helper/Debug.php +125 -0
  24. app/code/community/Flagbit/FactFinder/Helper/Search.php +232 -0
  25. app/code/community/Flagbit/FactFinder/Model/Adapter.php +817 -0
  26. app/code/community/Flagbit/FactFinder/Model/Export/Price.php +91 -0
  27. app/code/community/Flagbit/FactFinder/Model/Export/Product.php +535 -0
  28. app/code/community/Flagbit/FactFinder/Model/Export/Stock.php +91 -0
  29. app/code/community/Flagbit/FactFinder/Model/Layer.php +83 -0
  30. app/code/community/Flagbit/FactFinder/Model/Layer/Abstract.php +7 -0
  31. app/code/community/Flagbit/FactFinder/Model/Layer/Filter/Attribute/Abstract.php +118 -0
  32. app/code/community/Flagbit/FactFinder/Model/Layer/Filter/Attribute/Catalog.php +25 -0
  33. app/code/community/Flagbit/FactFinder/Model/Layer/Filter/Attribute/Catalogsearch.php +35 -0
  34. app/code/community/Flagbit/FactFinder/Model/Layer/Filter/Item.php +23 -0
  35. app/code/community/Flagbit/FactFinder/Model/Mysql4/Campaign/Pushedproducts/Collection.php +148 -0
  36. app/code/community/Flagbit/FactFinder/Model/Mysql4/Product/Attribute/Collection.php +144 -0
  37. app/code/community/Flagbit/FactFinder/Model/Mysql4/Product/Recommendation/Collection.php +59 -0
  38. app/code/community/Flagbit/FactFinder/Model/Mysql4/Scic/Queue.php +31 -0
  39. app/code/community/Flagbit/FactFinder/Model/Mysql4/Scic/Queue/Collection.php +28 -0
  40. app/code/community/Flagbit/FactFinder/Model/Mysql4/Search/Collection.php +130 -0
  41. app/code/community/Flagbit/FactFinder/Model/Mysql4/Search/Engine.php +53 -0
  42. app/code/community/Flagbit/FactFinder/Model/Observer.php +281 -0
  43. app/code/community/Flagbit/FactFinder/Model/Processor.php +260 -0
  44. app/code/community/Flagbit/FactFinder/Model/Scic/Queue.php +27 -0
  45. app/code/community/Flagbit/FactFinder/Model/System/Config/Backend/Attributes.php +52 -0
  46. app/code/community/Flagbit/FactFinder/Model/System/Config/Backend/Enabled.php +57 -0
  47. app/code/community/Flagbit/FactFinder/Model/System/Config/Source/Authtype.php +45 -0
  48. app/code/community/Flagbit/FactFinder/Model/System/Config/Source/Identifier.php +41 -0
  49. app/code/community/Flagbit/FactFinder/controllers/Adminhtml/Factfinder/CockpitController.php +53 -0
  50. app/code/community/Flagbit/FactFinder/controllers/ExportController.php +89 -0
  51. app/code/community/Flagbit/FactFinder/controllers/ProxyController.php +46 -0
  52. app/code/community/Flagbit/FactFinder/documentation/Installation_FACT-Finder_Magento_de.pdf +0 -0
  53. app/code/community/Flagbit/FactFinder/documentation/Installation_FACT-Finder_Magento_en.pdf +0 -0
  54. app/code/community/Flagbit/FactFinder/etc/adminhtml.xml +49 -0
  55. app/code/community/Flagbit/FactFinder/etc/config.xml +292 -0
  56. app/code/community/Flagbit/FactFinder/etc/system.xml +323 -0
  57. app/code/community/Flagbit/FactFinder/sql/factfinder_setup/mysql4-install-3.2.0.php +38 -0
  58. app/code/community/Flagbit/FactFinder/sql/factfinder_setup/mysql4-upgrade-3.2.0-3.2.1.php +30 -0
  59. app/code/community/Flagbit/FactFinder/sql/factfinder_setup/mysql4-upgrade-3.2.1-3.3.0.php +34 -0
  60. app/design/adminhtml/default/default/layout/factfinder.xml +28 -0
  61. app/design/adminhtml/default/default/template/factfinder/cockpit.phtml +22 -0
  62. app/design/frontend/base/default/layout/factfinder.xml +70 -0
  63. app/design/frontend/base/default/template/factfinder/campaign/advisory.phtml +12 -0
  64. app/design/frontend/base/default/template/factfinder/campaign/cart/advisory.phtml +12 -0
  65. app/design/frontend/base/default/template/factfinder/campaign/cart/feedback.phtml +6 -0
  66. app/design/frontend/base/default/template/factfinder/campaign/feedback.phtml +14 -0
  67. app/design/frontend/base/default/template/factfinder/filter/slider.phtml +46 -0
  68. app/design/frontend/base/default/template/factfinder/form.mini.phtml +38 -0
  69. app/design/frontend/base/default/template/factfinder/logo.phtml +22 -0
  70. app/design/frontend/base/default/template/factfinder/scic.phtml +31 -0
  71. app/etc/factfinder.xml +29 -0
  72. app/etc/modules/Flagbit_FactFinder.xml +9 -0
  73. app/locale/de_DE/Flagbit_FactFinder.csv +54 -0
  74. js/factfinder/jXHR.js +84 -0
  75. js/factfinder/scic.js +59 -0
  76. js/factfinder/suggest.js +185 -0
  77. lib/FACTFinder/Abstract/Adapter.php +118 -0
  78. lib/FACTFinder/Abstract/CompareAdapter.php +89 -0
  79. lib/FACTFinder/Abstract/Configuration.php +153 -0
  80. lib/FACTFinder/Abstract/DataProvider.php +112 -0
  81. lib/FACTFinder/Abstract/ProductCampaignAdapter.php +100 -0
  82. lib/FACTFinder/Abstract/RecommendationAdapter.php +87 -0
  83. lib/FACTFinder/Abstract/ScicAdapter.php +152 -0
  84. lib/FACTFinder/Abstract/SearchAdapter.php +252 -0
  85. lib/FACTFinder/Abstract/SimilarRecordsAdapter.php +121 -0
  86. lib/FACTFinder/Abstract/SuggestAdapter.php +33 -0
  87. lib/FACTFinder/Abstract/TagCloudAdapter.php +30 -0
  88. lib/FACTFinder/AdvisorAnswer.php +69 -0
  89. lib/FACTFinder/AdvisorQuestion.php +59 -0
  90. lib/FACTFinder/Asn.php +30 -0
  91. lib/FACTFinder/AsnFilterItem.php +65 -0
  92. lib/FACTFinder/AsnGroup.php +128 -0
  93. lib/FACTFinder/AsnSliderFilter.php +124 -0
  94. lib/FACTFinder/BreadCrumbItem.php +68 -0
  95. lib/FACTFinder/Campaign.php +198 -0
  96. lib/FACTFinder/CampaignIterator.php +182 -0
  97. lib/FACTFinder/Configuration.php +362 -0
  98. lib/FACTFinder/EncodingHandler.php +209 -0
  99. lib/FACTFinder/Http/DataProvider.php +291 -0
  100. lib/FACTFinder/Http/DummyProvider.php +130 -0
  101. lib/FACTFinder/Http/ParallelDataProvider.php +159 -0
  102. lib/FACTFinder/Http/ScicAdapter.php +29 -0
  103. lib/FACTFinder/Http/SuggestAdapter.php +35 -0
  104. lib/FACTFinder/Item.php +48 -0
  105. lib/FACTFinder/Loader.php +185 -0
  106. lib/FACTFinder/Logger/BlackHole.php +7 -0
  107. lib/FACTFinder/Logger/LoggerInterface.php +6 -0
  108. lib/FACTFinder/Paging.php +170 -0
  109. lib/FACTFinder/Parameters.php +106 -0
  110. lib/FACTFinder/ParametersParser.php +372 -0
  111. lib/FACTFinder/ProductsPerPageOptions.php +79 -0
  112. lib/FACTFinder/Record.php +251 -0
  113. lib/FACTFinder/Result.php +34 -0
  114. lib/FACTFinder/SingleWordSearchItem.php +39 -0
  115. lib/FACTFinder/SuggestQuery.php +71 -0
  116. lib/FACTFinder/TagQuery.php +41 -0
  117. lib/FACTFinder/Util.php +48 -0
  118. lib/FACTFinder/Xml64/SearchAdapter.php +111 -0
  119. lib/FACTFinder/Xml65/RecommendationAdapter.php +83 -0
  120. lib/FACTFinder/Xml65/SearchAdapter.php +493 -0
  121. lib/FACTFinder/Xml65/SuggestAdapter.php +59 -0
  122. lib/FACTFinder/Xml65/TagCloudAdapter.php +61 -0
  123. lib/FACTFinder/Xml66/CompareAdapter.php +101 -0
  124. lib/FACTFinder/Xml66/RecommendationAdapter.php +15 -0
  125. lib/FACTFinder/Xml66/SearchAdapter.php +115 -0
  126. lib/FACTFinder/Xml66/SimilarRecordsAdapter.php +106 -0
  127. lib/FACTFinder/Xml66/SuggestAdapter.php +15 -0
  128. lib/FACTFinder/Xml66/TagCloudAdapter.php +15 -0
  129. lib/FACTFinder/Xml67/CompareAdapter.php +12 -0
  130. lib/FACTFinder/Xml67/ProductCampaignAdapter.php +161 -0
  131. lib/FACTFinder/Xml67/RecommendationAdapter.php +33 -0
  132. lib/FACTFinder/Xml67/SearchAdapter.php +128 -0
  133. lib/FACTFinder/Xml67/SimilarRecordsAdapter.php +12 -0
  134. lib/FACTFinder/Xml67/SuggestAdapter.php +12 -0
  135. lib/FACTFinder/Xml67/TagCloudAdapter.php +12 -0
  136. lib/FACTFinderCustom/Configuration.php +297 -0
  137. package.xml +22 -0
app/code/community/Flagbit/FactFinder/Block/Adminhtml/Cockpit.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Black class
12
+ *
13
+ * This Block class provides the FACT-Finder Business User Cockpit Authentication URL
14
+ *
15
+ * @category Mage
16
+ * @package Flagbit_FactFinder
17
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
18
+ * @author Joerg Weller <weller@flagbit.de>
19
+ * @version $Id$
20
+ */
21
+ class Flagbit_FactFinder_Block_Adminhtml_Cockpit extends Mage_Adminhtml_Block_Template {
22
+
23
+ /**
24
+ * get FACT-Finder Business User Cockpit Authentication URL
25
+ *
26
+ * @return string
27
+ */
28
+ public function getAuthenticationUrl()
29
+ {
30
+ return Mage::getSingleton('factfinder/adapter')->getAuthenticationUrl();
31
+ }
32
+
33
+ }
app/code/community/Flagbit/FactFinder/Block/Adminhtml/Form/Field/Attribute.php ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Flagbit_FactFinder_Block_Adminhtml_Form_Field_Attribute extends Mage_Core_Block_Html_Select
4
+ {
5
+ /**
6
+ * Storeviews cache
7
+ *
8
+ * @var array
9
+ */
10
+ private $_attributes;
11
+
12
+ /**
13
+ * Retrieve allowed Storeviews
14
+ *
15
+ * @param int $storeId return name by storeview id
16
+ * @return array|string
17
+ */
18
+ protected function _getAttributes($storeId = null)
19
+ {
20
+ if (is_null($this->_attributes)) {
21
+ $this->_attributes = array();
22
+ $collection = Mage::getModel('eav/entity_attribute')->getCollection();
23
+ $collection->setEntityTypeFilter(Mage::getSingleton('eav/config')->getEntityType('catalog_product'));
24
+ foreach ($collection as $item) {
25
+ /* @var $item Mage_Core_Model_Store */
26
+ $this->_attributes[$item->getAttributeCode()] = $item->getFrontendLabel().' ('.$item->getAttributeCode().')';
27
+ }
28
+ }
29
+ if (!is_null($storeId)) {
30
+ return isset($this->_attributes[$storeId]) ? $this->_attributes[$storeId] : null;
31
+ }
32
+ return $this->_attributes;
33
+ }
34
+
35
+ public function setInputName($value)
36
+ {
37
+ return $this->setName($value);
38
+ }
39
+
40
+ /**
41
+ * Render block HTML
42
+ *
43
+ * @return string
44
+ */
45
+ public function _toHtml()
46
+ {
47
+ if (!$this->getOptions()) {
48
+ foreach ($this->_getAttributes() as $id => $label) {
49
+ $this->addOption($id, addslashes($label));
50
+ }
51
+ }
52
+ return parent::_toHtml();
53
+ }
54
+ }
app/code/community/Flagbit/FactFinder/Block/Adminhtml/Form/Field/Attributes.php ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_CatalogInventory
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ /**
28
+ * Adminhtml catalog inventory "Minimum Qty Allowed in Shopping Cart" field
29
+ *
30
+ * @category Mage
31
+ * @package Mage_CatalogInventory
32
+ * @author Magento Core Team <core@magentocommerce.com>
33
+ */
34
+ class Flagbit_FactFinder_Block_Adminhtml_Form_Field_Attributes extends Mage_Adminhtml_Block_System_Config_Form_Field_Array_Abstract
35
+ {
36
+ /**
37
+ * @var Flagbit_ContentFromUrl_Block_Adminhtml_Form_Field_Storeview
38
+ */
39
+ protected $_attributeRenderer;
40
+
41
+ /**
42
+ * Retrieve group column renderer
43
+ *
44
+ * @return Flagbit_ContentFromUrl_Block_Adminhtml_Form_Field_Storeview
45
+ */
46
+ protected function _getAttributeRenderer()
47
+ {
48
+ if (!$this->_attributeRenderer) {
49
+ $this->_attributeRenderer = $this->getLayout()->createBlock(
50
+ 'factfinder/adminhtml_form_field_attribute', '',
51
+ array('is_render_to_js_template' => true)
52
+ );
53
+ $this->_attributeRenderer->setClass('attribute_select');
54
+ $this->_attributeRenderer->setExtraParams('style="width:200px"');
55
+ }
56
+ return $this->_attributeRenderer;
57
+ }
58
+
59
+ /**
60
+ * Prepare to render
61
+ */
62
+ protected function _prepareToRender()
63
+ {
64
+ $this->addColumn('attribute', array(
65
+ 'label' => Mage::helper('factfinder')->__('Attribute'),
66
+ 'renderer' => $this->_getAttributeRenderer(),
67
+ ));
68
+
69
+ $this->_addAfter = false;
70
+ $this->_addButtonLabel = Mage::helper('factfinder')->__('Add Attribute');
71
+ }
72
+
73
+ /**
74
+ * Prepare existing row data object
75
+ *
76
+ * @param Varien_Object
77
+ */
78
+ protected function _prepareArrayRow(Varien_Object $row)
79
+ {
80
+ $row->setData(
81
+ 'option_extra_attr_' . $this->_getAttributeRenderer()->calcOptionHash($row->getData('attribute')),
82
+ 'selected="selected"'
83
+ );
84
+ }
85
+ }
app/code/community/Flagbit/FactFinder/Block/Campaign/Advisory.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Flagbit_FactFinder_Block_Campaign_Advisory extends Mage_Core_Block_Template
4
+ {
5
+ /**
6
+ * get Campaign Text
7
+ *
8
+ * @return string
9
+ */
10
+ public function getActiveQuestions()
11
+ {
12
+ $questions = array();
13
+
14
+ if(Mage::helper('factfinder/search')->getIsEnabled(false, 'campaign')){
15
+ $_campaigns = Mage::getSingleton('factfinder/adapter')->getCampaigns();
16
+ if($_campaigns && $_campaigns->hasActiveQuestions()){
17
+ $questions = $_campaigns->getActiveQuestions();
18
+ }
19
+ }
20
+
21
+ return $questions;
22
+ }
23
+ }
app/code/community/Flagbit/FactFinder/Block/Campaign/Cart/Advisory.php ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Provides advisory hints to the product view page
12
+ *
13
+ * @category Mage
14
+ * @package Flagbit_FactFinder
15
+ * @copyright Copyright (c) 2012 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
16
+ * @author Mike Becker <mike.becker@flagbit.de>
17
+ * @version $Id$
18
+ */
19
+ class Flagbit_FactFinder_Block_Campaign_Cart_Advisory extends Mage_Core_Block_Template
20
+ {
21
+ /**
22
+ * get campaign questions and answers
23
+ *
24
+ * @return array $questions
25
+ */
26
+ public function getActiveQuestions()
27
+ {
28
+ Mage::getSingleton('core/session', array('name'=>'frontend'));
29
+
30
+ if (!Mage::helper('factfinder/search')->getIsEnabled(false, 'campaign')) {
31
+ return array();
32
+ }
33
+
34
+ // only display campaign right after a new product was added to cart
35
+ if (!Mage::getSingleton('checkout/session')->getLastAddedProductId()) {
36
+ return array();
37
+ }
38
+
39
+ $questions = array();
40
+
41
+ $_product = Mage::getModel('catalog/product')->load(Mage::getSingleton('checkout/session')->getLastAddedProductId());
42
+ if (!$_product->getData(Mage::helper('factfinder/search')->getIdFieldName())) {
43
+ return array();
44
+ }
45
+
46
+ $_campaigns = Mage::helper('factfinder/search')->getProductCampaigns(array(
47
+ $_product->getData(Mage::helper('factfinder/search')->getIdFieldName())
48
+ ));
49
+
50
+ if($_campaigns && $_campaigns->hasActiveQuestions()){
51
+ $questions = $_campaigns->getActiveQuestions();
52
+ }
53
+
54
+ return $questions;
55
+ }
56
+ }
app/code/community/Flagbit/FactFinder/Block/Campaign/Cart/Feedback.php ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Provides advisory hints to the product view page
12
+ *
13
+ * @category Mage
14
+ * @package Flagbit_FactFinder
15
+ * @copyright Copyright (c) 2012 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
16
+ * @author Mike Becker <mike.becker@flagbit.de>
17
+ * @version $Id$
18
+ */
19
+ class Flagbit_FactFinder_Block_Campaign_Cart_Feedback extends Mage_Core_Block_Template
20
+ {
21
+ /**
22
+ * get campaign questions and answers
23
+ *
24
+ * @return array $feedback
25
+ */
26
+ public function getActiveFeedback()
27
+ {
28
+ Mage::getSingleton('core/session', array('name'=>'frontend'));
29
+
30
+ // only display campaign if they are activated and right after a new product was added to cart
31
+ if (!Mage::helper('factfinder/search')->getIsEnabled(false, 'campaign') || !Mage::getSingleton('checkout/session')->getLastAddedProductId()) {
32
+ return array();
33
+ }
34
+
35
+ $feedback = array();
36
+
37
+ $_product = Mage::getModel('catalog/product')->load(Mage::getSingleton('checkout/session')->getLastAddedProductId());
38
+ if (!$_product->getData(Mage::helper('factfinder/search')->getIdFieldName())) {
39
+ return array();
40
+ }
41
+
42
+ $_campaigns = Mage::helper('factfinder/search')->getProductCampaigns(array(
43
+ $_product->getData(Mage::helper('factfinder/search')->getIdFieldName())
44
+ ));
45
+
46
+ if($_campaigns && $_campaigns->hasFeedback()){
47
+ $feedback = $_campaigns;
48
+ }
49
+
50
+ return $feedback;
51
+
52
+ }
53
+ }
app/code/community/Flagbit/FactFinder/Block/Campaign/Feedback.php ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Block class
12
+ *
13
+ * This class is used to disable Magento´s default Price and Category Filter Output
14
+ *
15
+ * @category Mage
16
+ * @package Flagbit_FactFinder
17
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
18
+ * @author Joerg Weller <weller@flagbit.de>
19
+ * @version $Id: Scic.php 645 2011-03-17 14:54:20Z weller $
20
+ */
21
+ class Flagbit_FactFinder_Block_Campaign_Feedback extends Mage_Core_Block_Template
22
+ {
23
+ /**
24
+ * Pushed Products Collection
25
+ *
26
+ * @var Flagbit_FactFinder_Model_Mysql4_Campaign_Pushedproducts_Collection
27
+ */
28
+ protected $_pushedProductsCollection = null;
29
+
30
+ /**
31
+ * get Campaign Text
32
+ *
33
+ * @return string
34
+ */
35
+ public function getText()
36
+ {
37
+ $text = '';
38
+
39
+ if(Mage::helper('factfinder/search')->getIsEnabled(false, 'campaign')){
40
+ $_campaigns = Mage::getSingleton('factfinder/adapter')->getCampaigns();
41
+ if($_campaigns && $_campaigns->hasFeedback() && $this->getTextNumber()){
42
+ $text = $_campaigns->getFeedback($this->getTextNumber() - 1);
43
+ }
44
+ }
45
+
46
+ return $text;
47
+ }
48
+
49
+ /**
50
+ * Pushed Products Collection
51
+ *
52
+ * @return Flagbit_FactFinder_Model_Mysql4_Campaign_Pushedproducts_Collection
53
+ */
54
+ public function getPushedProductsCollection()
55
+ {
56
+ if($this->_pushedProductsCollection === null){
57
+ $this->_pushedProductsCollection = Mage::getResourceModel('factfinder/campaign_pushedproducts_collection');
58
+ }
59
+
60
+ return $this->_pushedProductsCollection;
61
+ }
62
+ }
app/code/community/Flagbit/FactFinder/Block/Campaign/Product/Advisory.php ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Provides advisory hints to the product view page
12
+ *
13
+ * @category Mage
14
+ * @package Flagbit_FactFinder
15
+ * @copyright Copyright (c) 2012 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
16
+ * @author Mike Becker <mike.becker@flagbit.de>
17
+ * @version $Id$
18
+ */
19
+ class Flagbit_FactFinder_Block_Campaign_Product_Advisory extends Mage_Core_Block_Template
20
+ {
21
+ /**
22
+ * get campaign questions and answers
23
+ *
24
+ * @return array $questions
25
+ */
26
+ public function getActiveQuestions()
27
+ {
28
+ $questions = array();
29
+
30
+ if (Mage::helper('factfinder/search')->getIsEnabled(false, 'campaign') && Mage::registry('current_product')) {
31
+ $_campaigns = Mage::helper('factfinder/search')->getProductCampaigns(array(
32
+ Mage::registry('current_product')->getData(Mage::helper('factfinder/search')->getIdFieldName()),
33
+ ));
34
+
35
+ if($_campaigns && $_campaigns->hasActiveQuestions()){
36
+ $questions = $_campaigns->getActiveQuestions();
37
+ }
38
+ }
39
+
40
+ return $questions;
41
+ }
42
+ }
app/code/community/Flagbit/FactFinder/Block/Campaign/Product/Feedback.php ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Provides advisory hints to the product view page
12
+ *
13
+ * @category Mage
14
+ * @package Flagbit_FactFinder
15
+ * @copyright Copyright (c) 2012 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
16
+ * @author Mike Becker <mike.becker@flagbit.de>
17
+ * @version $Id$
18
+ */
19
+ class Flagbit_FactFinder_Block_Campaign_Product_Feedback extends Mage_Core_Block_Template
20
+ {
21
+ /**
22
+ * get campaign feedback
23
+ *
24
+ * @return array $feedback
25
+ */
26
+ public function getActiveFeedback()
27
+ {
28
+ $feedback = array();
29
+
30
+ if (Mage::helper('factfinder/search')->getIsEnabled(false, 'campaign') && Mage::registry('current_product')) {
31
+ $_campaigns = Mage::helper('factfinder/search')->getProductCampaigns(array(
32
+ Mage::registry('current_product')->getData(Mage::helper('factfinder/search')->getIdFieldName()),
33
+ ));
34
+
35
+ if($_campaigns && $_campaigns->hasFeedback()){
36
+ $feedback = $_campaigns;
37
+ }
38
+ }
39
+
40
+ return $feedback;
41
+ }
42
+ }
app/code/community/Flagbit/FactFinder/Block/Cart/Crosssell.php ADDED
@@ -0,0 +1,93 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Overwritten block.
12
+ *
13
+ * Replaces the crosssell block within cart view. Gets data from FACT-Finder instead of product link collection.
14
+ *
15
+ * @category Mage
16
+ * @package Flagbit_FactFinder
17
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
18
+ * @author Michael Türk <tuerk@flagbit.de>
19
+ * @version $Id: Processor.php 647 2011-03-21 10:32:14Z rudolf_batt $
20
+ */
21
+ class Flagbit_FactFinder_Block_Cart_Crosssell extends Mage_Checkout_Block_Cart_Crosssell
22
+ {
23
+ /**
24
+ * Overwritten function. Gets information from FACT-Finder Collection instead of product link collection.
25
+ */
26
+ public function getItems()
27
+ {
28
+ if (!Mage::getStoreConfigFlag('factfinder/activation/crosssell')) {
29
+ return parent::getItems();
30
+ }
31
+
32
+ $items = $this->getData('items');
33
+ if (is_null($items)) {
34
+ try {
35
+ $items = array();
36
+ $ninProductIds = $this->_getCartProductIds();
37
+ if ($ninProductIds) {
38
+ $lastAdded = (int) $this->_getLastAddedProductId();
39
+ if ($lastAdded) {
40
+ $searchHelper = Mage::helper('factfinder/search');
41
+ $idFieldName = $searchHelper->getIdFieldName();
42
+
43
+ $recommendationAdapter = Mage::getModel('factfinder/adapter')->getRecommendationAdapter();
44
+ $attributeValue = Mage::getModel('catalog/product')->getResource()->getAttributeRawValue($lastAdded, $idFieldName, Mage::app()->getStore()->getId());
45
+
46
+ $collection = $this->_getCollection()
47
+ ->setRecommendations($recommendationAdapter->getRecommendations($attributeValue));
48
+ if (!empty($ninProductIds)) {
49
+ $collection->addExcludeProductFilter($ninProductIds);
50
+ }
51
+
52
+ foreach ($collection as $item) {
53
+ $items[] = $item;
54
+ }
55
+ }
56
+
57
+ }
58
+ }
59
+ catch (Exception $e) {
60
+ Mage::logException($e);
61
+ $items = array();
62
+ }
63
+
64
+ $this->setData('items', $items);
65
+ }
66
+ return $items;
67
+ }
68
+
69
+ /**
70
+ * Get crosssell products collection. Get it from product recommendation collection for communication with FACT-Finder.
71
+ *
72
+ * @return Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Link_Product_Collection
73
+ */
74
+ protected function _getCollection()
75
+ {
76
+ if (!Mage::getStoreConfigFlag('factfinder/activation/crosssell')) {
77
+ return parent::_getCollection();
78
+ }
79
+
80
+ $collection = Mage::getResourceModel('factfinder/product_recommendation_collection')
81
+ ->addAttributeToSelect(Mage::getSingleton('catalog/config')->getProductAttributes())
82
+ ->setStoreId(Mage::app()->getStore()->getId())
83
+ ->addStoreFilter()
84
+ ->setPageSize($this->_maxItemCount);
85
+ $this->_addProductAttributesAndPrices($collection);
86
+
87
+ Mage::getSingleton('catalog/product_status')->addSaleableFilterToCollection($collection);
88
+ Mage::getSingleton('catalog/product_visibility')->addVisibleInCatalogFilterToCollection($collection);
89
+ Mage::getSingleton('cataloginventory/stock')->addInStockFilterToCollection($collection);
90
+
91
+ return $collection;
92
+ }
93
+ }
app/code/community/Flagbit/FactFinder/Block/Filter/Slider.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Block class
12
+ *
13
+ * Add Slider Javascript to HTML Head
14
+ *
15
+ * @category Mage
16
+ * @package Flagbit_FactFinder
17
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
18
+ * @author Joerg Weller <weller@flagbit.de>
19
+ * @version $Id$
20
+ */
21
+ class Flagbit_FactFinder_Block_Filter_Slider extends Mage_Core_Block_Abstract {
22
+
23
+ /**
24
+ * get Slider Javascript
25
+ *
26
+ * @return string
27
+ */
28
+ protected function _toHtml()
29
+ {
30
+ if(Mage::helper('factfinder/search')->getIsEnabled()){
31
+ return '<script type="text/javascript" language="javascript" src="http://static.express.fact-finder.com/onetouchslider-1.0/de.factfinder.asn.slider.OneTouchSlider.nocache.js"></script>'."\n".
32
+ '<script type="text/javascript" language="javascript"> oneTouchSliderOnLoad = function(){ document.fire("ffslider:init");}</script>'."\n";
33
+
34
+ }
35
+ }
36
+ }
app/code/community/Flagbit/FactFinder/Block/Layer.php ADDED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Block class
12
+ *
13
+ * This class is used to disable Magento´s default Price and Category Filter Output
14
+ *
15
+ * @category Mage
16
+ * @package Flagbit_FactFinder
17
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
18
+ * @author Joerg Weller <weller@flagbit.de>
19
+ * @version $Id$
20
+ */
21
+ class Flagbit_FactFinder_Block_Layer extends Flagbit_FactFinder_Block_Layer_Abstract
22
+ {
23
+
24
+ /**
25
+ * Prepare child blocks
26
+ *
27
+ * @return Mage_Catalog_Block_Layer_View
28
+ */
29
+ protected function _prepareLayout()
30
+ {
31
+ if(Mage::helper('factfinder/search')->getIsEnabled(false, 'campaign')){
32
+ // handle redirects
33
+ $redirect = Mage::getSingleton('factfinder/adapter')->getRedirect();
34
+ if($redirect){
35
+ Mage::app()->getResponse()->setRedirect($redirect);
36
+ }
37
+ }
38
+
39
+ if(!Mage::helper('factfinder/search')->getIsEnabled(false, 'asn')){
40
+ return parent::_prepareLayout();
41
+ }
42
+
43
+ // set default sort Order
44
+ if(Mage::getSingleton('catalog/session')->getSortOrder()){
45
+ Mage::getSingleton('catalog/session')->setSortOrder('relevance');
46
+ }
47
+
48
+ $stateBlock = $this->getLayout()->createBlock('catalog/layer_state')
49
+ ->setLayer($this->getLayer());
50
+
51
+ $this->setChild('layer_state', $stateBlock);
52
+
53
+ $filterableAttributes = $this->_getFilterableAttributes();
54
+ foreach ($filterableAttributes as $attribute) {
55
+ $filterBlockName = $this->_getAttributeFilterBlockName();
56
+
57
+ $filterBlock = $this->getLayout()->createBlock($filterBlockName)
58
+ ->setLayer($this->getLayer())
59
+ ->setAttributeModel($attribute)
60
+ ->init();
61
+
62
+ switch($attribute->getType()){
63
+
64
+ case 'slider':
65
+ if(!($this->getLayout()->getBlock('ffslider') instanceof Flagbit_FactFinder_Block_Filter_Slider)){
66
+ $this->getLayout()->getBlock('head')->setChild('ffslider', $this->getLayout()->createBlock('factfinder/filter_slider'));
67
+ }
68
+ $filterBlock->setTemplate('factfinder/filter/slider.phtml');
69
+ $filterBlock->setData((current($attribute->getItems())));
70
+ $filterBlock->setUnit($attribute->getUnit());
71
+ break;
72
+ }
73
+
74
+ $this->setChild($attribute->getAttributeCode().'_filter', $filterBlock);
75
+ }
76
+
77
+ $this->getLayer()->apply();
78
+ return Mage_Core_Block_Template::_prepareLayout();
79
+ }
80
+
81
+ /**
82
+ * Get category filter block
83
+ *
84
+ * @return Mage_Catalog_Block_Layer_Filter_Category
85
+ */
86
+ protected function _getCategoryFilter()
87
+ {
88
+ if(!Mage::helper('factfinder/search')->getIsEnabled(false, 'asn')){
89
+ return parent::_getCategoryFilter();
90
+ }
91
+ return false;
92
+ }
93
+
94
+ /**
95
+ * Retrieve Price Filter block
96
+ *
97
+ * @return Mage_Catalog_Block_Layer_Filter_Price
98
+ */
99
+ protected function _getPriceFilter()
100
+ {
101
+ if(!Mage::helper('factfinder/search')->getIsEnabled(false, 'asn')){
102
+ return parent::_getPriceFilter();
103
+ }
104
+
105
+ return false;
106
+ }
107
+
108
+ /**
109
+ * Check availability display layer block
110
+ *
111
+ * @return bool
112
+ */
113
+ public function canShowBlock()
114
+ {
115
+ if (!Mage::helper('factfinder/search')->getIsEnabled(false)) {
116
+ return parent::canShowBlock();
117
+ }
118
+ if(!Mage::helper('factfinder/search')->getIsEnabled(false, 'asn')){
119
+ return false;
120
+ }
121
+ if ($this->getLayer()->getFilterableAttributes()->count()
122
+ && $this->getLayer()->getProductCollection()->getSize()) {
123
+ return true;
124
+ }
125
+ return false;
126
+ }
127
+ }
app/code/community/Flagbit/FactFinder/Block/Layer/Abstract.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Block class
12
+ *
13
+ * dynamicaly extends the core class whether Enterprise Search is enabled or not
14
+ *
15
+ * @category Mage
16
+ * @package Flagbit_FactFinder
17
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
18
+ * @author Joerg Weller <weller@flagbit.de>
19
+ * @version $Id$
20
+ */
21
+
22
+ if(Mage::helper('factfinder/search')->getIsOnSearchPage()){
23
+ if(Mage::helper('factfinder')->isModuleActive('Enterprise_Search')){
24
+ class Flagbit_FactFinder_Block_Layer_Abstract extends Enterprise_Search_Block_Catalogsearch_Layer {}
25
+ }else{
26
+ class Flagbit_FactFinder_Block_Layer_Abstract extends Mage_CatalogSearch_Block_Layer {}
27
+ }
28
+ }else{
29
+ class Flagbit_FactFinder_Block_Layer_Abstract extends Mage_Catalog_Block_Layer_View {}
30
+ }
31
+
32
+
33
+
app/code/community/Flagbit/FactFinder/Block/Product/List/Crosssell.php ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Overwritten block.
12
+ *
13
+ * Replaces the crosssell block. Gets data from FACT-Finder instead of product link collection.
14
+ *
15
+ * @category Mage
16
+ * @package Flagbit_FactFinder
17
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
18
+ * @author Michael Türk <tuerk@flagbit.de>
19
+ * @version $Id: Processor.php 647 2011-03-21 10:32:14Z rudolf_batt $
20
+ */
21
+ class Flagbit_FactFinder_Block_Product_List_Crosssell extends Mage_Catalog_Block_Product_List_Crosssell
22
+ {
23
+ /**
24
+ * Method overwritten. Data is not read from product link collection but from FACT-Finder interface instead.
25
+ */
26
+ protected function _prepareData()
27
+ {
28
+
29
+ if (!Mage::getStoreConfigFlag('factfinder/activation/crosssell')) {
30
+ return parent::_prepareData();
31
+ }
32
+ try {
33
+ $product = Mage::registry('product');
34
+ /* @var $product Mage_Catalog_Model_Product */
35
+
36
+ $searchHelper = Mage::helper('factfinder/search');
37
+ $idFieldName = $searchHelper->getIdFieldName();
38
+
39
+ $this->_itemCollection = Mage::getResourceModel('factfinder/product_recommendation_collection')
40
+ ->addAttributeToSelect(Mage::getSingleton('catalog/config')->getProductAttributes())
41
+ ->addStoreFilter();
42
+
43
+ $recommendationAdapter = Mage::getModel('factfinder/adapter')->getRecommendationAdapter();
44
+ $recommendationAdapter->setProductId($product->getData($idFieldName));
45
+ $recommendations = $recommendationAdapter->getRecommendations();
46
+ $this->_itemCollection->setRecommendations($recommendations);
47
+
48
+ Mage::getSingleton('catalog/product_visibility')->addVisibleInCatalogFilterToCollection($this->_itemCollection);
49
+
50
+ $this->_itemCollection->load();
51
+
52
+ foreach ($this->_itemCollection as $product) {
53
+ $product->setDoNotUseCategoryId(true);
54
+ }
55
+ }
56
+ catch (Exception $e) {
57
+ Mage::logException($e);
58
+ $this->_itemCollection = new Varien_Data_Collection();
59
+ }
60
+
61
+ return $this;
62
+ }
63
+ }
app/code/community/Flagbit/FactFinder/Block/Product/List/Upsell.php ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Block class for upselling
12
+ *
13
+ * Rewritten block - data is now caught by FACT-Finder, passed to normal collection, works quite as if it was the
14
+ * default behavior.
15
+ *
16
+ * @category Mage
17
+ * @package Flagbit_FactFinder
18
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
19
+ * @author Michael Türk <türk@flagbit.de>
20
+ * @version $Id: Search.php 678 2011-08-01 13:02:50Z rudolf_batt $
21
+ */
22
+ class Flagbit_FactFinder_Block_Product_List_Upsell extends Mage_Catalog_Block_Product_List_Upsell
23
+ {
24
+ /**
25
+ * Method overwritten. Data is not read from product link collection but from FACT-Finder interface instead.
26
+ */
27
+ protected function _prepareData()
28
+ {
29
+ if (!Mage::getStoreConfigFlag('factfinder/activation/upsell') && !(Mage::helper('factfinder/search')->getIsEnabled(false, 'campaign'))) {
30
+ return parent::_prepareData();
31
+ }
32
+
33
+ try {
34
+ $product = Mage::registry('product');
35
+ /* @var $product Mage_Catalog_Model_Product */
36
+
37
+ $searchHelper = Mage::helper('factfinder/search');
38
+ $idFieldName = $searchHelper->getIdFieldName();
39
+
40
+ $recommendationAdapter = Mage::getModel('factfinder/adapter')->getRecommendationAdapter();
41
+ $recommendationAdapter->setProductId($product->getData($idFieldName));
42
+ $recommendations = $recommendationAdapter->getRecommendations();
43
+
44
+ // combine recommendations and pushed products
45
+ $mergedUpsell = array_merge($this->getPushedProducts(), (array) $recommendations);
46
+ // build new FACTFinder_Result with combined data
47
+ $recommendations = FF::getInstance('result', $mergedUpsell, count($mergedUpsell));
48
+
49
+ if ($recommendations == null) {
50
+ throw new Exception('No recommendations given - check connection to FACT-Finder and FACT-Finder configuration');
51
+ }
52
+ elseif ($recommendations->getFoundRecordsCount() == 0) {
53
+ $this->_itemCollection = new Varien_Data_Collection();
54
+ return $this;
55
+ }
56
+
57
+ $this->_itemCollection = Mage::getResourceModel('factfinder/product_recommendation_collection')->addStoreFilter();
58
+
59
+ if ($this->getItemLimit('upsell') > 0) {
60
+ $this->_itemCollection->setPageSize($this->getItemLimit('upsell'));
61
+ }
62
+ $this->_itemCollection->setRecommendations($recommendations);
63
+
64
+ Mage::getResourceSingleton('checkout/cart')->addExcludeProductFilter($this->_itemCollection,
65
+ Mage::getSingleton('checkout/session')->getQuoteId()
66
+ );
67
+ $this->_addProductAttributesAndPrices($this->_itemCollection);
68
+
69
+ // // Mage::getSingleton('catalog/product_status')->addSaleableFilterToCollection($this->_itemCollection);
70
+ Mage::getSingleton('catalog/product_visibility')->addVisibleInCatalogFilterToCollection($this->_itemCollection);
71
+ $this->_itemCollection->load();
72
+
73
+ /**
74
+ * Updating collection with desired items
75
+ */
76
+ Mage::dispatchEvent('catalog_product_upsell', array(
77
+ 'product' => $product,
78
+ 'collection' => $this->_itemCollection,
79
+ 'limit' => $this->getItemLimit()
80
+ ));
81
+
82
+ foreach ($this->_itemCollection as $product) {
83
+ $product->setDoNotUseCategoryId(true);
84
+ }
85
+ }
86
+ catch (Exception $e) {
87
+ Mage::logException($e);
88
+ $this->_itemCollection = new Varien_Data_Collection();
89
+ }
90
+
91
+ return $this;
92
+ }
93
+
94
+
95
+ /**
96
+ * get pushed products to combine with recommendations
97
+ *
98
+ * @return array
99
+ */
100
+ protected function getPushedProducts()
101
+ {
102
+ $pushedProducts = array();
103
+
104
+ $_campaigns = Mage::helper('factfinder/search')->getProductCampaigns(array(
105
+ Mage::registry('current_product')->getData(Mage::helper('factfinder/search')->getIdFieldName()),
106
+ ));
107
+
108
+ if($_campaigns && $_campaigns->hasPushedProducts()){
109
+ $pushedProducts = $_campaigns->getPushedProducts();
110
+ }
111
+
112
+ return $pushedProducts;
113
+ }
114
+
115
+ }
app/code/community/Flagbit/FactFinder/Block/Scic.php ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Block class
12
+ *
13
+ * This class is used to disable Magento´s default Price and Category Filter Output
14
+ *
15
+ * @category Mage
16
+ * @package Flagbit_FactFinder
17
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
18
+ * @author Joerg Weller <weller@flagbit.de>
19
+ * @version $Id$
20
+ */
21
+ class Flagbit_FactFinder_Block_Scic extends Mage_Core_Block_Template
22
+ {
23
+
24
+ /**
25
+ * get Product Result Collection
26
+ *
27
+ * @return Flagbit_FactFinder_Model_Mysql4_Search_Collection
28
+ */
29
+ protected function _getProductResultCollection()
30
+ {
31
+ return Mage::getSingleton('factfinder/layer')->getProductCollection();
32
+ }
33
+
34
+ /**
35
+ * get Product URL to ID Mapping JSON Object
36
+ *
37
+ * @return string
38
+ */
39
+ public function getJsonUrlToIdMappingObject()
40
+ {
41
+ $data = array();
42
+ foreach($this->_getProductResultCollection() as $product){
43
+ $data[$product->getProductUrl()] = $product->getId();
44
+ }
45
+ return Mage::helper('core')->jsonEncode($data);
46
+ }
47
+
48
+ /**
49
+ * get Product and Search Details by ID as JSON Object
50
+ *
51
+ * @return string
52
+ */
53
+ public function getJsonDataObject()
54
+ {
55
+ $searchHelper = Mage::helper('factfinder/search');
56
+ $idFieldName = $searchHelper->getIdFieldName();
57
+
58
+ $dataTemplate = array(
59
+ 'query' => $searchHelper->getQuery()->getQueryText(),
60
+ 'page' => $searchHelper->getCurrentPage(),
61
+ 'sid' => md5(Mage::getSingleton('core/session')->getSessionId()),
62
+ 'pageSize' => $searchHelper->getPageLimit(),
63
+ 'origPageSize' => $searchHelper->getDefaultPerPageValue(),
64
+ 'channel' => Mage::getStoreConfig('factfinder/search/channel'),
65
+ 'event' => 'click'
66
+ );
67
+
68
+ $customerId = Mage::getSingleton('customer/session')->getCustomer()->getId();
69
+ if ($customerId) {
70
+ $dataTemplate['userId'] = md5('customer_' . $customerId);
71
+ }
72
+
73
+ $data = array();
74
+ foreach($this->_getProductResultCollection() as $product){
75
+ $key = $product->getId();
76
+ $data[$key] = array(
77
+ 'id' => $product->getData($idFieldName),
78
+ 'pos' => $product->getPosition(),
79
+ 'origPos' => $product->getOriginalPosition(),
80
+ 'title' => $product->getName(),
81
+ 'simi' => $product->getSimilarity()
82
+ );
83
+ $data[$key] += $dataTemplate;
84
+ }
85
+
86
+ return Mage::helper('core')->jsonEncode($data);
87
+ }
88
+
89
+ }
app/code/community/Flagbit/FactFinder/Block/TagCloud.php ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Flagbit_FactFinder_Block_TagCloud extends Mage_CatalogSearch_Block_Term
3
+ {
4
+ protected function _loadTerms()
5
+ {
6
+ if (!Mage::helper('factfinder/search')->getIsEnabled(false, 'tagcloud')) {
7
+ return parent::_loadTerms();
8
+ }
9
+
10
+ if (empty($this->_terms)) {
11
+ $terms = Mage::getSingleton('factfinder/adapter')->getTagCloud();
12
+
13
+ if (count($terms) == 0) {
14
+ return $this;
15
+ }
16
+
17
+ $this->_maxPopularity = 0;
18
+ $this->_minPopularity = 1;
19
+
20
+ for ($i = 0; $i < count($terms); $i++) {
21
+ $term = $terms[$i];
22
+
23
+ $termArray = array();
24
+ $termArray['name'] = $term->getValue();
25
+ $termArray['url'] = $term->getUrl();
26
+ $termArray['popularity'] = $term->getWeight();
27
+ $termArray['ratio'] = $term->getWeight();
28
+
29
+ if ($term->getWeight() > $this->_maxPopularity) {
30
+ $this->_maxPopularity = $term->getWeight();
31
+ }
32
+ if ($term->getWeight() < $this->_minPopularity) {
33
+ $this->_minPopularity = $term->getWeight();
34
+ }
35
+
36
+ $terms[$i] = new Varien_Object($termArray);
37
+ }
38
+
39
+ $this->_terms = $terms;
40
+ }
41
+
42
+ return $this;
43
+ }
44
+ }
app/code/community/Flagbit/FactFinder/Block/XmlConnect/Catalog/Product/List.php ADDED
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Block class
12
+ *
13
+ * This class is used to disable Magento´s default apply Filter
14
+ *
15
+ * @category Mage
16
+ * @package Flagbit_FactFinder
17
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
18
+ * @author Joerg Weller <weller@flagbit.de>
19
+ * @version $Id$
20
+ */
21
+ class Flagbit_FactFinder_Block_XmlConnect_Catalog_Product_List extends Mage_XmlConnect_Block_Catalog_Product_List {
22
+
23
+ /**
24
+ * Retrieve product collection with all prepared data and limitations
25
+ *
26
+ * @return Mage_Eav_Model_Entity_Collection_Abstract
27
+ */
28
+ protected function _getProductCollection()
29
+ {
30
+ if(!Mage::helper('factfinder/search')->getIsEnabled()){
31
+ return parent::_getProductCollection();
32
+ }
33
+
34
+ if (is_null($this->_productCollection)) {
35
+ switch($this->getRequest()->getActionName()){
36
+
37
+ case 'search':
38
+ $this->__getSearchProductCollection();
39
+ break;
40
+
41
+ default:
42
+ parent::_getProductCollection();
43
+ break;
44
+ }
45
+ }
46
+ return $this->_productCollection;
47
+ }
48
+
49
+
50
+ /**
51
+ * Retrieve product collection with all prepared data and limitations
52
+ *
53
+ * @return Mage_Eav_Model_Entity_Collection_Abstract
54
+ */
55
+ protected function __getSearchProductCollection()
56
+ {
57
+ if (is_null($this->_productCollection)) {
58
+ $filters = array();
59
+ $request = $this->getRequest();
60
+ $requestParams = $request->getParams();
61
+ $layer = $this->getLayer();
62
+ if (!$layer) {
63
+ return null;
64
+ }
65
+ $category = $this->getCategory();
66
+ if ($category && is_object($category) && $category->getId()) {
67
+ $layer->setCurrentCategory($category);
68
+ }
69
+
70
+ if (!$this->getNeedBlockApplyingFilters()) {
71
+ $attributes = $layer->getFilterableAttributes();
72
+ /**
73
+ * Apply filters
74
+ */
75
+ foreach ($attributes as $attributeItem) {
76
+
77
+ $attributeCode = $attributeItem->getAttributeCode();
78
+ $filterModel = $this->helper('xmlconnect')->getFilterByKey($attributeCode);
79
+
80
+ $filterModel->setLayer($layer)
81
+ ->setAttributeModel($attributeItem);
82
+
83
+ $filterParam = parent::REQUEST_FILTER_PARAM_REFIX . $attributeCode;
84
+ $filters[] = $filterModel;
85
+ }
86
+ $this->_collectedFilters = $filters;
87
+ }
88
+
89
+ /**
90
+ * Products
91
+ */
92
+ $layer = $this->getLayer();
93
+ $collection = $layer->getProductCollection();
94
+
95
+ /**
96
+ * Add rating and review summary, image attribute, apply sort params
97
+ */
98
+ $this->_prepareCollection($collection);
99
+
100
+ /**
101
+ * Apply offset and count
102
+ */
103
+ $offset = (int)$request->getParam('offset', 0);
104
+ $count = (int)$request->getParam('count', 0);
105
+ $count = $count <= 0 ? 1 : $count;
106
+ if($offset + $count < $collection->getSize()){
107
+ $this->setHasProductItems(1);
108
+ }
109
+ $collection->getSelect()->limit($count, $offset);
110
+
111
+ $collection->setFlag('require_stock_items', true);
112
+
113
+ $this->_productCollection = $collection;
114
+ }
115
+
116
+ return $this->_productCollection;
117
+ }
118
+
119
+
120
+ }
121
+
122
+
123
+
124
+
app/code/community/Flagbit/FactFinder/Block/XmlConnect/Catalog/Search.php ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Block class
12
+ *
13
+ * This class is used provide FAC-Finder filters
14
+ *
15
+ * @category Mage
16
+ * @package Flagbit_FactFinder
17
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
18
+ * @author Joerg Weller <weller@flagbit.de>
19
+ * @version $Id$
20
+ */
21
+ class Flagbit_FactFinder_Block_XmlConnect_Catalog_Search extends Mage_XmlConnect_Block_Catalog_Search {
22
+
23
+
24
+ /**
25
+ * Search results xml renderer
26
+ * XML also contains filters that can be apply (accorfingly already applyed filters and search query)
27
+ * and sort fields
28
+ *
29
+ * @return string
30
+ */
31
+ protected function _toHtml()
32
+ {
33
+ if(!Mage::helper('factfinder/search')->getIsEnabled()){
34
+ return parent::_toHtml();
35
+ }
36
+
37
+ $searchXmlObject = new Mage_XmlConnect_Model_Simplexml_Element('<search></search>');
38
+ $filtersXmlObject = new Mage_XmlConnect_Model_Simplexml_Element('<filters></filters>');
39
+
40
+ $helper = Mage::helper('catalogsearch');
41
+ if (method_exists($helper, 'getEngine')) {
42
+ $engine = Mage::helper('catalogsearch')->getEngine();
43
+ $isLayeredNavigationAllowed = ($engine instanceof Varien_Object) ? $engine->isLeyeredNavigationAllowed() : true;
44
+ }
45
+ else {
46
+ $isLayeredNavigationAllowed = true;
47
+ }
48
+
49
+ $request = $this->getRequest();
50
+ $requestParams = $request->getParams();
51
+ $hasMoreProductItems = 0;
52
+
53
+ /**
54
+ * Products
55
+ */
56
+ $productListBlock = $this->getChild('product_list');
57
+ $productListBlock->setNeedBlockApplyingFilters(false);
58
+ if ($productListBlock) {
59
+ $layer = Mage::getSingleton('catalogsearch/layer');
60
+ $productsXmlObj = $productListBlock->setLayer($layer)
61
+ ->setNeedBlockApplyingFilters(!$isLayeredNavigationAllowed)
62
+ ->getProductsXmlObject();
63
+ $searchXmlObject->appendChild($productsXmlObj);
64
+ $hasMoreProductItems = (int)$productListBlock->getHasProductItems();
65
+ }
66
+
67
+ $searchXmlObject->addAttribute('has_more_items', $hasMoreProductItems);
68
+
69
+ /**
70
+ * Filters
71
+ */
72
+ $showFiltersAndOrders = true;
73
+ $reguest = $this->getRequest();
74
+ foreach ($reguest->getParams() as $key => $value) {
75
+ if (0 === strpos($key, parent::REQUEST_SORT_ORDER_PARAM_REFIX) ||
76
+ 0 === strpos($key, parent::REQUEST_FILTER_PARAM_REFIX)) {
77
+ $showFiltersAndOrders = false;
78
+ break;
79
+ }
80
+ }
81
+ if ($isLayeredNavigationAllowed && $productListBlock && $showFiltersAndOrders) {
82
+ $filters = $productListBlock->getCollectedFilters();
83
+
84
+ /**
85
+ * Render filters xml
86
+ */
87
+ foreach ($filters as $filter) {
88
+ if (!count($filter->getAttributeModel()->getItems())) {
89
+ continue;
90
+ }
91
+
92
+ $item = $filtersXmlObject->addChild('item');
93
+ $item->addChild('name', $searchXmlObject->xmlentities($filter->getName()));
94
+ $item->addChild('code', $filter->getRequestVar());
95
+ $values = $item->addChild('values');
96
+
97
+ foreach ($filter->getAttributeModel()->getItems() as $valueArray) {
98
+ $valueItem = new Varien_Object($valueArray);
99
+ $count = (int)$valueItem->getCount();
100
+ if (!$count) {
101
+ continue;
102
+ }
103
+ $value = $values->addChild('value');
104
+ $value->addChild('id', base64_encode($valueItem->getValue()));
105
+ $value->addChild('label', $searchXmlObject->xmlentities(strip_tags($valueItem->getLabel())));
106
+ $value->addChild('count', $count);
107
+ }
108
+ }
109
+ $searchXmlObject->appendChild($filtersXmlObject);
110
+ }
111
+
112
+ /**
113
+ * Sort fields
114
+ */
115
+ if ($showFiltersAndOrders) {
116
+ $searchXmlObject->appendChild($this->getProductSortFeildsXmlObject());
117
+ }
118
+
119
+ return $searchXmlObject->asNiceXml();
120
+ }
121
+
122
+
123
+ }
app/code/community/Flagbit/FactFinder/Block/XmlConnect/Catalog/Search/Suggest.php ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Block class
12
+ *
13
+ * This class enables FAC-Finder sugguest
14
+ *
15
+ * @category Mage
16
+ * @package Flagbit_FactFinder
17
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
18
+ * @author Joerg Weller <weller@flagbit.de>
19
+ * @version $Id$
20
+ */
21
+ class Flagbit_FactFinder_Block_XmlConnect_Catalog_Search_Suggest extends Mage_XmlConnect_Block_Catalog_Search_Suggest
22
+ {
23
+ const SUGGEST_ITEM_SEPARATOR = '::sep::';
24
+
25
+ /**
26
+ * Search suggestions xml renderer
27
+ *
28
+ * @return string
29
+ */
30
+ protected function _toHtml()
31
+ {
32
+ $suggestXmlObj = new Mage_XmlConnect_Model_Simplexml_Element('<suggestions></suggestions>');
33
+ if (!$this->getRequest()->getParam('q', false)) {
34
+ return $suggestXmlObj->asNiceXml();
35
+ }
36
+
37
+ $suggestData = Mage::getSingleton('factfinder/adapter')->getSuggestResult($this->getRequest()->getParam('q'));
38
+
39
+ if (!($count = count($suggestData))) {
40
+ return $suggestXmlObj->asNiceXml();
41
+ }
42
+
43
+ $items = '';
44
+ foreach ($suggestData as $index => $item) {
45
+ $items .= $suggestXmlObj->xmlentities(strip_tags($item['query']))
46
+ . self::SUGGEST_ITEM_SEPARATOR
47
+ . (int)$item['hitCount']
48
+ . self::SUGGEST_ITEM_SEPARATOR;
49
+ }
50
+
51
+ $suggestXmlObj = new Mage_XmlConnect_Model_Simplexml_Element('<suggestions>' . $items . '</suggestions>');
52
+
53
+ return $suggestXmlObj->asNiceXml();
54
+ }
55
+
56
+ }
app/code/community/Flagbit/FactFinder/Helper/Backend.php ADDED
@@ -0,0 +1,228 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Helper class
12
+ *
13
+ * Helper for backend configurations.
14
+ *
15
+ * @category Mage
16
+ * @package Flagbit_FactFinder
17
+ * @copyright Copyright (c) 2011 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
18
+ * @author Michael Türk <tuerk@flagbit.de>
19
+ * @version $Id: Enabled.php 647 2011-03-21 10:32:14Z rudolf_batt $
20
+ */
21
+ class Flagbit_FactFinder_Helper_Backend extends Mage_Core_Helper_Abstract
22
+ {
23
+
24
+ /**
25
+ * Check configuration data by contacting FACT-Finder servers.
26
+ *
27
+ * @param unknown_type $configData
28
+ */
29
+ public function checkConfigData($configData) {
30
+ $dataArray = $this->_getCompleteFieldsetData($configData);
31
+ $data = new Varien_Object($dataArray);
32
+ $errors = array();
33
+
34
+ if (stripos($data->getAddress(), 'http://') === 0 || strpos($data->getAddress(), '/') !== false) {
35
+ $errors[] = Mage::helper('factfinder')->__('servername should only contain the IP address or the domain - no "http://" or any slashes!');
36
+ }
37
+
38
+ if ($data->getPort() == '') {
39
+ $port = 80;
40
+ }
41
+ elseif (!is_numeric($data->getPort())) {
42
+ $errors[] = Mage::helper('factfinder')->__('the value for "port" must be numeric!');
43
+ }
44
+ elseif(intval($data->getPort()) < 80) { //is there any http port lower 80?
45
+ $errors[] = Mage::helper('factfinder')->__('the value for "port" must be a number greater or equals 80!');
46
+ }
47
+
48
+ if ($data->getAuthPassword() != '' && $data->getAuthUser() == '') {
49
+ $errors[] = Mage::helper('factfinder')->__('there must be a username, if a password should be used');
50
+ }
51
+
52
+ $conflicts = Mage::helper('factfinder/debug')->getRewriteConflicts();
53
+ if(count($conflicts)){
54
+ foreach($conflicts as $moduleClass => $externalClass){
55
+ $errors[] = Mage::helper('factfinder')->__('There is a Class Rewrite Conflict: "%s" already overwritten by "%s"', $moduleClass, $externalClass);
56
+ }
57
+ }
58
+
59
+ if (count($errors) == 0) {
60
+ $adapter = Mage::getSingleton('factfinder/adapter');
61
+ if(!$adapter->checkStatus($dataArray)){
62
+ $errors[] = Mage::helper('factfinder')->__('WARNING: was not able to connect to FACT-Finder.');
63
+ }
64
+ }
65
+
66
+ return $errors;
67
+ }
68
+
69
+
70
+
71
+ /**
72
+ * Read data from array given, or if no value given, try to read data from website or global configuration
73
+ *
74
+ * @param array $configData
75
+ */
76
+ protected function _getCompleteFieldsetData($configData)
77
+ {
78
+ $data = array();
79
+ $websiteCode = Mage::app()->getRequest()->getParam('website');
80
+ $storeCode = Mage::app()->getRequest()->getParam('store');
81
+
82
+ foreach ($configData as $key => $keyData) {
83
+ if (!isset($keyData['value'])) {
84
+
85
+ $path = 'factfinder/search/' . $key;
86
+
87
+ if ($storeCode) {
88
+ $value = Mage::app()->getWebsite($websiteCode)->getConfig($path);
89
+ }
90
+ else {
91
+ $value = (string) Mage::getConfig()->getNode('default/' . $path);
92
+ }
93
+ }
94
+ else {
95
+ $value = $keyData['value'];
96
+ }
97
+
98
+ $data[$key] = $value;
99
+ }
100
+
101
+ return $data;
102
+ }
103
+
104
+ /**
105
+ * Generate a storable representation of a value
106
+ *
107
+ * @param mixed $value
108
+ * @return string
109
+ */
110
+ protected function _serializeValue($value)
111
+ {
112
+ if (is_array($value)) {
113
+ $data = array();
114
+ foreach ($value as $rule => $setup) {
115
+ if($rule == '__empty') {
116
+ continue;
117
+ }
118
+ if (!array_key_exists($rule, $data)) {
119
+ $data[$rule] = $setup;
120
+ }
121
+ }
122
+ return serialize($data);
123
+ } else {
124
+ return '';
125
+ }
126
+ }
127
+
128
+ /**
129
+ * Create a value from a storable representation
130
+ *
131
+ * @param mixed $value
132
+ * @return array
133
+ */
134
+ protected function _unserializeValue($value)
135
+ {
136
+ if (is_string($value) && !empty($value)) {
137
+ return unserialize($value);
138
+ } else {
139
+ return array();
140
+ }
141
+ }
142
+
143
+ /**
144
+ * Check whether value is in form retrieved by _encodeArrayFieldValue()
145
+ *
146
+ * @param mixed
147
+ * @return bool
148
+ */
149
+ protected function _isEncodedArrayFieldValue($value)
150
+ {
151
+ if (!is_array($value)) {
152
+ return false;
153
+ }
154
+ unset($value['__empty']);
155
+ foreach ($value as $_id => $row) {
156
+ if (!is_array($row) || !array_key_exists('attribute', $row)) {
157
+ return false;
158
+ }
159
+ }
160
+ return true;
161
+ }
162
+
163
+ /**
164
+ * Encode value to be used in Mage_Adminhtml_Block_System_Config_Form_Field_Array_Abstract
165
+ *
166
+ * @param array
167
+ * @return array
168
+ */
169
+ protected function _encodeArrayFieldValue(array $value)
170
+ {
171
+ $result = array();
172
+ foreach ($value as $set => $value) {
173
+ $_id = Mage::helper('core')->uniqHash('_');
174
+ $result[$_id] = $value;
175
+ }
176
+ return $result;
177
+ }
178
+
179
+ /**
180
+ * Decode value from used in Mage_Adminhtml_Block_System_Config_Form_Field_Array_Abstract
181
+ *
182
+ * @param array
183
+ * @return array
184
+ */
185
+ protected function _decodeArrayFieldValue(array $value)
186
+ {
187
+ $result = array();
188
+ unset($value['__empty']);
189
+ foreach ($value as $_id => $row) {
190
+ if (!is_array($row) || !array_key_exists('attribute', $row)) {
191
+ continue;
192
+ }
193
+ $result[trim($row['attribute'])] = $row;
194
+ }
195
+ return $result;
196
+ }
197
+
198
+ /**
199
+ * Make value readable by Mage_Adminhtml_Block_System_Config_Form_Field_Array_Abstract
200
+ *
201
+ * @param mixed $value
202
+ * @return array
203
+ */
204
+ public function makeArrayFieldValue($value)
205
+ {
206
+ $value = $this->_unserializeValue($value);
207
+ if (!$this->_isEncodedArrayFieldValue($value)) {
208
+ $value = $this->_encodeArrayFieldValue($value);
209
+ }
210
+ return $value;
211
+ }
212
+
213
+ /**
214
+ * Make value ready for store
215
+ *
216
+ * @param mixed $value
217
+ * @return string
218
+ */
219
+ public function makeStorableArrayFieldValue($value)
220
+ {
221
+ if ($this->_isEncodedArrayFieldValue($value)) {
222
+ $value = $this->_decodeArrayFieldValue($value);
223
+ }
224
+ $value = $this->_serializeValue($value);
225
+ return $value;
226
+ }
227
+
228
+ }
app/code/community/Flagbit/FactFinder/Helper/Data.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Helper class
12
+ *
13
+ * This helper class provides Translation Methods throw Magento Helper Abstract
14
+ *
15
+ * @category Mage
16
+ * @package Flagbit_FactFinder
17
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
18
+ * @author Joerg Weller <weller@flagbit.de>
19
+ * @version $Id$
20
+ */
21
+ class Flagbit_FactFinder_Helper_Data extends Mage_Core_Helper_Abstract {
22
+
23
+ /**
24
+ * returns Module Status by Module Code
25
+ *
26
+ * @param string $code Module Code
27
+ * @return boolean
28
+ */
29
+ public function isModuleActive($code)
30
+ {
31
+ $module = Mage::getConfig()->getNode("modules/$code");
32
+ $model = Mage::getConfig()->getNode("global/models/$code");
33
+ return $module && $module->is('active') || $model;
34
+ }
35
+
36
+ }
app/code/community/Flagbit/FactFinder/Helper/Debug.php ADDED
@@ -0,0 +1,125 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Helper class
12
+ *
13
+ * This helper class provides some Methods which allows us
14
+ * to debug Modul specific configurations Problems.
15
+ *
16
+ * @category Mage
17
+ * @package Flagbit_FactFinder
18
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
19
+ * @author Joerg Weller <weller@flagbit.de>
20
+ * @version $Id$
21
+ */
22
+ class Flagbit_FactFinder_Helper_Debug extends Mage_Core_Helper_Abstract
23
+ implements FACTFinder_Logger_LoggerInterface
24
+ {
25
+ /**
26
+ * Module Configuration File
27
+ *
28
+ * @var string
29
+ */
30
+ const MODULE_CONFIG_FILE = 'config.xml';
31
+
32
+ /**
33
+ * Module Log File
34
+ *
35
+ * @var string
36
+ */
37
+ const LOG_FILE_NAME = 'factfinder.log';
38
+
39
+ /**
40
+ * XML Config Path to Product Identifier Setting
41
+ *
42
+ * @var string
43
+ */
44
+ const XML_CONFIG_PATH_DEBUG_MODE = 'factfinder/config/debug';
45
+
46
+ /**
47
+ * Debug Log to file var/log/factfinder.log
48
+ *
49
+ * @param $message
50
+ * @param $level
51
+ * @param $file
52
+ * @param $forceLog
53
+ */
54
+ public function log($message)
55
+ {
56
+ if (!Mage::getConfig()) {
57
+ return;
58
+ }
59
+ try{
60
+ if(Mage::getStoreConfig(self::XML_CONFIG_PATH_DEBUG_MODE)) {
61
+ return Mage::log($message, null, self::LOG_FILE_NAME, true);
62
+ }
63
+ }catch (Exception $e){}
64
+
65
+ return $this;
66
+ }
67
+
68
+ public function error($error)
69
+ {
70
+ return $this->log('ERROR: ' . $error);
71
+ }
72
+
73
+ public function info($message)
74
+ {
75
+ return $this->log('INFO: ' . $message);
76
+ }
77
+
78
+ /**
79
+ * get Class Rewrite Conflicts for the current Modul
80
+ *
81
+ * return array
82
+ */
83
+ public function getRewriteConflicts()
84
+ {
85
+ $rewriteConflicts = array();
86
+ $xml = simplexml_load_file(Mage::getConfig()->getModuleDir('etc', $this->_getModuleName()).DS.self::MODULE_CONFIG_FILE);
87
+ if ($xml instanceof SimpleXMLElement) {
88
+ $rewriteNodes = $xml->xpath('//rewrite');
89
+
90
+ foreach ($rewriteNodes as $n) {
91
+ $nParent = $n->xpath('..');
92
+ $module = (string) $nParent[0]->getName();
93
+ $nParent2 = $nParent[0]->xpath('..');
94
+ $component = (string) $nParent2[0]->getName();
95
+ $pathNodes = $n->children();
96
+
97
+ foreach ($pathNodes as $pathNode) {
98
+
99
+ $path = (string) $pathNode->getName();
100
+ $completePath = $module.'/'.$path;
101
+
102
+ $rewriteClassName = (string) $pathNode;
103
+
104
+ $instance = Mage::getConfig()->getGroupedClassName(
105
+ substr($component, 0, -1),
106
+ $completePath
107
+ );
108
+ if($instance != $rewriteClassName){
109
+
110
+ try{
111
+ $reflector = new $instance();
112
+ if($reflector instanceof $rewriteClassName){
113
+ continue;
114
+ }
115
+ }catch (Exception $e){}
116
+
117
+ $rewriteConflicts[$rewriteClassName] = $instance;
118
+ }
119
+ }
120
+ }
121
+ }
122
+ return $rewriteConflicts;
123
+ }
124
+
125
+ }
app/code/community/Flagbit/FactFinder/Helper/Search.php ADDED
@@ -0,0 +1,232 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Helper class
12
+ *
13
+ * This helper class provides some Methods which allows us
14
+ * to get default und current Values from Toolbar block.
15
+ *
16
+ * @category Mage
17
+ * @package Flagbit_FactFinder
18
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
19
+ * @author Joerg Weller <weller@flagbit.de>
20
+ * @version $Id$
21
+ */
22
+ class Flagbit_FactFinder_Helper_Search extends Mage_Core_Helper_Abstract {
23
+
24
+ /**
25
+ * XML Config Path to Product Identifier Setting
26
+ *
27
+ * @var string
28
+ */
29
+ const XML_CONFIG_PATH_PRODUCT_IDENTIFIER = 'factfinder/config/identifier';
30
+
31
+ /**
32
+ * XML Config Path to Product Identifier Setting
33
+ *
34
+ * @var string
35
+ */
36
+ const XML_CONFIG_PATH_USE_PROXY = 'factfinder/config/proxy';
37
+
38
+ /**
39
+ * if FACT-Finder enabled?
40
+ *
41
+ * @return boolean
42
+ */
43
+ public function getIsEnabled($searchPageCheck = true, $functionality = '')
44
+ {
45
+ if (!Mage::getStoreConfigFlag('factfinder/search/enabled')
46
+ || Mage::getStoreConfigFlag('advanced/modules_disable_output/Flagbit_FactFinder')
47
+ || ($searchPageCheck == true && !$this->getIsOnSearchPage() && !Mage::getStoreConfigFlag('factfinder/activation/navigation'))) {
48
+ return false;
49
+ }
50
+
51
+ $result = true;
52
+
53
+ if ($functionality) {
54
+ switch ($functionality) {
55
+ case 'suggest':
56
+ $result = Mage::getStoreConfig('factfinder/activation/suggest');
57
+ break;
58
+ case 'asn':
59
+ if (Mage::helper('factfinder/search')->getIsOnSearchPage()) {
60
+ $result = Mage::getStoreConfig('factfinder/activation/asn');
61
+ }
62
+ else {
63
+ $result = Mage::getStoreConfig('factfinder/activation/navigation');
64
+ }
65
+ break;
66
+ case 'campaign':
67
+ $result = Mage::getStoreConfig('factfinder/activation/campaign');
68
+ break;
69
+ case 'clicktracking':
70
+ $result = Mage::getStoreConfig('factfinder/export/clicktracking');
71
+ break;
72
+ case 'tagcloud':
73
+ $result = Mage::getStoreConfig('factfinder/activation/tagcloud');
74
+ break;
75
+ }
76
+ }
77
+
78
+ return $result;
79
+ }
80
+
81
+ /**
82
+ * get Module Status depending on Module
83
+ *
84
+ * @return boolean
85
+ */
86
+ public function getIsOnSearchPage()
87
+ {
88
+ return Mage::app()->getRequest()->getModuleName() == 'catalogsearch' || Mage::app()->getRequest()->getModuleName() == 'xmlconnect';
89
+ }
90
+
91
+
92
+ /**
93
+ * get Toolbar Block
94
+ *
95
+ * @return Mage_Catalog_Block_Product_List_Toolbar
96
+ */
97
+ protected function _getToolbarBlock()
98
+ {
99
+ $mainBlock = Mage::app()->getLayout()->getBlock('search.result');
100
+ if($mainBlock instanceof Mage_CatalogSearch_Block_Result){
101
+ $toolbarBlock = $mainBlock->getListBlock()->getToolbarBlock();
102
+ }else{
103
+ $toolbarBlock = Mage::app()->getLayout()->createBlock('catalog/product_list_toolbar');
104
+ }
105
+
106
+ return $toolbarBlock;
107
+ }
108
+
109
+ /**
110
+ * Retrieve default per page values
111
+ *
112
+ * @return string (comma separated)
113
+ */
114
+ public function getDefaultPerPageValue()
115
+ {
116
+ return $this->_getToolbarBlock()->getDefaultPerPageValue();
117
+ }
118
+
119
+ /**
120
+ * get Entity ID Field Name by Configuration or via Entity
121
+ *
122
+ * @return string
123
+ */
124
+ public function getIdFieldName()
125
+ {
126
+ $idFieldName = Mage::getStoreConfig(self::XML_CONFIG_PATH_PRODUCT_IDENTIFIER);
127
+ if(!$idFieldName){
128
+ $idFieldName = $this->getEntity()->getIdFieldName();
129
+ }
130
+ return $idFieldName;
131
+ }
132
+
133
+ /**
134
+ * get FACT-Finder Suggest URL
135
+ *
136
+ * @return string
137
+ */
138
+ public function getSuggestUrl()
139
+ {
140
+ $url = Mage::getSingleton('factfinder/adapter')->getSuggestUrl();
141
+ if(Mage::getStoreConfig(self::XML_CONFIG_PATH_USE_PROXY)){
142
+ $url = $this->_getUrl('factfinder/proxy/suggest');
143
+ }
144
+ return $url;
145
+ }
146
+
147
+
148
+ /**
149
+ * get current Order
150
+ *
151
+ * @return string
152
+ */
153
+ public function getCurrentOrder()
154
+ {
155
+ return $this->_getToolbarBlock()->getCurrentOrder();
156
+ }
157
+
158
+ /**
159
+ * get current Order Direction
160
+ *
161
+ * @return string
162
+ */
163
+ public function getCurrentDirection()
164
+ {
165
+ return $this->_getToolbarBlock()->getCurrentDirection();
166
+ }
167
+
168
+ /**
169
+ * get Page Limit
170
+ *
171
+ * @return int
172
+ */
173
+ public function getPageLimit()
174
+ {
175
+ $limit = $this->_getToolbarBlock()->getLimit();
176
+ if ($limit == 'all') {
177
+ $limit = 2*3*4*5*6; //a lot of products working for each layout
178
+ }
179
+ return $limit;
180
+ }
181
+
182
+ /**
183
+ * get current Page Number
184
+ *
185
+ * @return int
186
+ */
187
+ public function getCurrentPage()
188
+ {
189
+ return $this->_getToolbarBlock()->getCurrentPage();
190
+ }
191
+
192
+ /**
193
+ * Retrieve query model object
194
+ *
195
+ * @return Mage_CatalogSearch_Model_Query
196
+ */
197
+ public function getQuery()
198
+ {
199
+ return Mage::helper('catalogsearch')->getQuery();
200
+ }
201
+
202
+ /**
203
+ * Retrieve query model object
204
+ *
205
+ * @return String
206
+ */
207
+ public function getQueryText()
208
+ {
209
+ return Mage::helper('catalogsearch')->getQueryText();
210
+ }
211
+
212
+
213
+ /**
214
+ * return product campaings
215
+ *
216
+ * @param array $productIds
217
+ * @return FACTFinder_CampaignIterator
218
+ */
219
+ public function getProductCampaigns($productIds)
220
+ {
221
+ try {
222
+ // get productcampaign adapter and set product id or sku array
223
+ $productCampaignAdapter = Mage::getModel('factfinder/adapter')->getProductCampaignAdapter();
224
+ $productCampaignAdapter->setProductIds($productIds);
225
+ $productCampaignAdapter->makeProductCampaign();
226
+
227
+ return $productCampaignAdapter->getCampaigns();
228
+ } catch(Exception $e) {
229
+ return array();
230
+ }
231
+ }
232
+ }
app/code/community/Flagbit/FactFinder/Model/Adapter.php ADDED
@@ -0,0 +1,817 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ require_once BP.DS.'lib'.DS.'FACTFinder'.DS.'Loader.php';
11
+
12
+ /**
13
+ * Model class
14
+ *
15
+ * Adapter between FACT-Finder API Framework and Magento
16
+ *
17
+ * @category Mage
18
+ * @package Flagbit_FactFinder
19
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
20
+ * @author Joerg Weller <weller@flagbit.de>
21
+ * @version $Id: Adapter.php 906 2011-09-30 14:10:05Z tuerk $
22
+ */
23
+ class Flagbit_FactFinder_Model_Adapter
24
+ {
25
+
26
+ /**
27
+ * FACT-Finder Searchadapter
28
+ * @var FACTFinder_Abstract_SearchAdapter
29
+ */
30
+ protected $_searchAdapter = null;
31
+
32
+ /**
33
+ * FACT-Finder Suggestadapter
34
+ * @var FACTFinder_Abstract_SuggestAdapter
35
+ */
36
+ protected $_suggestAdapter = null;
37
+
38
+ /**
39
+ * FACT-Finder Config
40
+ * @var FACTFinder_Abstract_Configuration
41
+ */
42
+ protected $_config = null;
43
+
44
+ /**
45
+ * FACT-Finder Parameter Parser
46
+ * @var FACTFinder_ParametersParser
47
+ */
48
+ protected $_paramsParser = null;
49
+
50
+ /**
51
+ * FACT-Finder Data Provider
52
+ * @var FACTFinder_Abstract_DataProvider
53
+ */
54
+ protected $_dataProvider = null;
55
+
56
+ /**
57
+ * FACT-Finder Scic Adapter
58
+ * @var FACTFinder_Abstract_ScicAdapter
59
+ */
60
+ protected $_scicAdapter = null;
61
+
62
+ /**
63
+ * FACT-Finder Recommendation Adapter
64
+ * @var FACTFinder_Abstract_RecommendationAdapter
65
+ */
66
+ protected $_recommendationAdapter = null;
67
+
68
+ /**
69
+ * FACT-Finder Product Campaign Adapter
70
+ * @var FACTFinder_Abstract_ProductCampaignAdapter
71
+ */
72
+ protected $_productCampaignAdapter = null;
73
+
74
+ /**
75
+ * FACT-Finder TagCloudadapter
76
+ * @var FACTFinder_Abstract_TagCloudAdapter
77
+ */
78
+ protected $_tagCloudAdapter = null;
79
+
80
+ /**
81
+ * FACT-Finder After Search Navigation
82
+ * @var array
83
+ */
84
+ protected $_afterSearchNavigation = null;
85
+
86
+ /**
87
+ * FACT-Finder Searchadapter
88
+ * @var array
89
+ */
90
+ protected $_searchResultProductIds = null;
91
+
92
+ /**
93
+ * current FACT-Finder Category Path
94
+ * @var array
95
+ */
96
+ protected $_currentFactfinderCategoryPath = null;
97
+
98
+
99
+ public function __construct($arg = null)
100
+ {
101
+ if ($arg != null && $arg instanceof FACTFinder_Logger_LoggerInterface) {
102
+ FF::setLogger($arg);
103
+ } else {
104
+ $logger = Mage::helper('factfinder/debug');
105
+ FF::setLogger($logger);
106
+ }
107
+ }
108
+
109
+ /**
110
+ * get FactFinder SearchAdapter
111
+ *
112
+ * @return FACTFinder_Abstract_SearchAdapter
113
+ */
114
+ protected function _getSearchAdapter($collectParams = true)
115
+ {
116
+ if ($this->_searchAdapter == null) {
117
+ $config = $this->_getConfiguration();
118
+ $encodingHandler = FF::getSingleton('encodingHandler', $config);
119
+ $dataProvider = $this->_getDataProvider();
120
+ $this->_searchAdapter = FF::getSingleton(
121
+ 'xml67/searchAdapter',
122
+ $dataProvider,
123
+ $this->_getParamsParser(),
124
+ $encodingHandler
125
+ );
126
+
127
+ if($collectParams == true){
128
+ $this->_collectParams();
129
+ }
130
+ }
131
+
132
+ return $this->_searchAdapter;
133
+ }
134
+
135
+ protected function _collectParams()
136
+ {
137
+ // search Helper
138
+ $helper = Mage::helper('factfinder/search');
139
+ $_request = Mage::app()->getRequest();
140
+ $params = $this->_getParamsParser()->getRequestParams();
141
+
142
+ if (strpos(Mage::getStoreConfig('factfinder/config/internal_ip'), Mage::helper('core/http')->getRemoteAddr()) !== false) {
143
+ $this->_setParam('log', 'internal');
144
+ }
145
+
146
+ switch($_request->getModuleName()){
147
+
148
+ case "xmlconnect":
149
+ $_query = $helper->getQueryText();
150
+ $this->_setParam('idsOnly', 'true')
151
+ ->_setParam('query', $_query);
152
+
153
+ $count = $params['count'];
154
+ if ($count > 0) {
155
+ $this->_setParam('productsPerPage', $count)
156
+ ->_setParam('page', ($params['offset'] / $count) + 1);
157
+ }
158
+
159
+ // add Sorting Param
160
+ foreach($params as $key => $value){
161
+ if(substr($key, 0, 6) == 'order_'){
162
+ $key = substr($key, 6);
163
+ if(!in_array($key, array('position', 'relevance'))){
164
+ $this->_setParam('sort'.$key, $value);
165
+ }
166
+ }
167
+ }
168
+
169
+ // add Filter Params
170
+ foreach($params as $key => $value){
171
+ $value = base64_decode($value);
172
+ if(strpos($value, '|')){
173
+ $param = explode('|', $value);
174
+ if($key == 'Category'){
175
+ $categories = array_merge(array_slice(explode('/', $param[0]), 1), array($param[1]));
176
+ foreach($categories AS $k => $v) { $categories[$k] = urldecode($v); }
177
+ $filterkey = '';
178
+ foreach($categories as $category){
179
+ $category = str_replace('%2F', '/', str_replace('%2B', '+', $category));
180
+ $this->_setParam('filtercategoryROOT'.$filterkey, $category);
181
+ $filterkey .= '/'.str_replace('+', '%2B', str_replace('/', '%2F', $category));
182
+ }
183
+ }else{
184
+ $this->_setParam('filter'.$param[0], $param[1]);
185
+ }
186
+ }
187
+ }
188
+
189
+ break;
190
+
191
+ case "catalog":
192
+ $_query = '*';
193
+ if (!isset($params['Category'])) {
194
+ $params['Category'] = $this->_getCurrentFactfinderCategoryPath();
195
+ }
196
+
197
+ case "catalogsearch":
198
+ default:
199
+ if ($_request->getModuleName() == 'catalogsearch') {
200
+ $_query = $helper->getQueryText();
201
+ }
202
+
203
+ // add Default Params
204
+ $this->_setParam('idsOnly', 'true')
205
+ ->_setParam('productsPerPage', $helper->getPageLimit())
206
+ ->_setParam('query', $_query)
207
+ ->_setParam('page', $helper->getCurrentPage());
208
+
209
+ // add Sorting Param, but only if it was set explicit via url
210
+ foreach($params as $key => $value){
211
+ if($key == 'order'
212
+ && $helper->getCurrentOrder()
213
+ && $helper->getCurrentDirection()
214
+ && $helper->getCurrentOrder() != 'position'
215
+ && $helper->getCurrentOrder() != 'relevance'){
216
+ $this->_setParam('sort'.$helper->getCurrentOrder(), $helper->getCurrentDirection());
217
+ }
218
+ }
219
+
220
+ // add Filter Params
221
+ foreach($params as $key => $value){
222
+ if(strpos($value, '|')){
223
+ $param = explode('|', $value);
224
+ switch($param[1]){
225
+
226
+ case 'slider':
227
+ $subparam = explode(':', $param[2]);
228
+ $this->_setParam($subparam[0], $subparam[1]);
229
+ $subparam = explode(':', $param[3]);
230
+ $this->_setParam($subparam[0], $subparam[1]);
231
+ break;
232
+
233
+ default:
234
+ if($key == 'Category'){
235
+ $categories = array_merge(array_slice(explode('/', $param[0]), 1), array($param[1]));
236
+ foreach($categories AS $k => $v) { $categories[$k] = $v; }
237
+ $filterkey = '';
238
+ foreach($categories as $category){
239
+ $category = str_replace('%2F', '/', str_replace('%2B', '+', $category));
240
+ $this->_setParam('filtercategoryROOT'.$filterkey, $category);
241
+ $filterkey .= '/'.str_replace('+', '%2B', str_replace('/', '%2F', $category));
242
+ }
243
+
244
+ }else{
245
+ $this->_setParam('filter'.$param[0], $param[1]);
246
+ }
247
+ break;
248
+ }
249
+ }
250
+ }
251
+ break;
252
+
253
+ }
254
+ }
255
+
256
+
257
+ /**
258
+ * execute search
259
+ */
260
+ public function checkStatus($configarray = null)
261
+ {
262
+ $status = false;
263
+ try {
264
+ $this->_getConfiguration($configarray);
265
+ $this->_setParam('query', 'FACT-Finder Version');
266
+ $this->_setParam('productsPerPage', '1');
267
+
268
+ $status = $this->_getSearchAdapter(false)->getStatus() == 'resultsFound';
269
+ } catch (Exception $e) {
270
+ $status = false;
271
+ }
272
+ return $status;
273
+ }
274
+
275
+ /**
276
+ * get Redirect URL if there is set one
277
+ *
278
+ * @return string
279
+ */
280
+ public function getRedirect()
281
+ {
282
+ $url = null;
283
+ $campaigns = $this->getCampaigns();
284
+
285
+ if (!empty($campaigns) && $campaigns->hasRedirect()) {
286
+ $url = $campaigns->getRedirectUrl();
287
+ }
288
+ return $url;
289
+ }
290
+
291
+ /**
292
+ *
293
+ */
294
+ public function getCampaigns()
295
+ {
296
+ $campaigns = null;
297
+ try {
298
+ $campaigns = $this->_getSearchAdapter()->getCampaigns();
299
+ }
300
+ catch (Exception $e) {
301
+ Mage::logException($e);
302
+ }
303
+ return $campaigns;
304
+ }
305
+
306
+ /**
307
+ * get Search Suggest URL
308
+ *
309
+ * @return string
310
+ */
311
+ public function getSuggestUrl()
312
+ {
313
+ $dataprovider = $this->_getDataProvider();
314
+ $dataprovider->setType('Suggest.ff');
315
+ $dataprovider->setParams(array());
316
+
317
+ return $dataprovider->getNonAuthenticationUrl();
318
+ }
319
+
320
+ /**
321
+ * get Suggest Adapter
322
+ *
323
+ * @return FACTFinder_Abstract_SuggestAdapter
324
+ */
325
+ protected function _getSuggestAdapter()
326
+ {
327
+ if ($this->_suggestAdapter == null) {
328
+ $config = $this->_getConfiguration();
329
+ $encodingHandler = FF::getSingleton('encodingHandler', $config);
330
+ $params = $this->_getParamsParser()->getServerRequestParams();
331
+ $dataProvider = $this->_getDataProvider();
332
+ $this->_suggestAdapter = FF::getSingleton('http/suggestAdapter', $dataProvider, $this->_getParamsParser(), $encodingHandler);
333
+ }
334
+
335
+ return $this->_suggestAdapter;
336
+ }
337
+
338
+ /**
339
+ * get Suggest Results as Array
340
+ *
341
+ * @param string $query
342
+ * @return array
343
+ */
344
+ public function getSuggestResult($query)
345
+ {
346
+ $this->_setParam('query', $query);
347
+ $this->_setParam('format', 'json');
348
+
349
+ return Zend_Json_Decoder::decode($this->_getSuggestAdapter()->getSuggestions());
350
+ }
351
+
352
+ /**
353
+ * get Suggest Results as JSON
354
+ *
355
+ * @param string $query
356
+ * @return string json
357
+ */
358
+ public function getSuggestResultJsonp($query, $jqueryCallback)
359
+ {
360
+ $this->_setParam('query', $query, false);
361
+ $this->_setParam('format', 'jsonp', false);
362
+
363
+ return $this->_getSuggestAdapter()->getSuggestions();
364
+ }
365
+
366
+ /**
367
+ * get FactFinder TagCloudAdapter
368
+ *
369
+ * @return FACTFinder_Abstract_TagCloudAdapter
370
+ */
371
+ protected function _getTagCloudAdapter()
372
+ {
373
+ if ($this->_tagCloudAdapter == null) {
374
+ $config = $this->_getConfiguration();
375
+ $encodingHandler = FF::getSingleton('encodingHandler', $config);
376
+ $dataProvider = $this->_getDataProvider();
377
+ $this->_tagCloudAdapter = FF::getSingleton(
378
+ 'xml67/tagCloudAdapter',
379
+ $dataProvider,
380
+ $this->_getParamsParser(),
381
+ $encodingHandler
382
+ );
383
+
384
+ }
385
+
386
+ return $this->_tagCloudAdapter;
387
+ }
388
+
389
+ /**
390
+ * get tag cloud information as Array
391
+ *
392
+ * @param string $query
393
+ * @return array
394
+ */
395
+ public function getTagCloud()
396
+ {
397
+ return $this->_getTagCloudAdapter()->getTagCloud();
398
+ }
399
+
400
+ /**
401
+ * get Scic Adapter
402
+ *
403
+ * @return FACTFinder_Abstract_ScicAdapter
404
+ */
405
+ public function getScicAdapter()
406
+ {
407
+ if ($this->_scicAdapter == null) {
408
+ $config = $this->_getConfiguration();
409
+ $encodingHandler = FF::getSingleton('encodingHandler', $config);
410
+ $params = $this->_getParamsParser()->getServerRequestParams();
411
+ $dataProvider = $this->_getDataProvider();
412
+ $this->_scicAdapter = FF::getSingleton('http/scicAdapter', $dataProvider, $this->_getParamsParser(), $encodingHandler);
413
+ }
414
+ return $this->_scicAdapter;
415
+ }
416
+
417
+ /**
418
+ * get Recommendation Adapter
419
+ *
420
+ * @return FACTFinder_Abstract_RecommendationAdapter
421
+ */
422
+ public function getRecommendationAdapter()
423
+ {
424
+ if ($this->_recommendationAdapter == null) {
425
+ $config = $this->_getConfiguration();
426
+ $encodingHandler = FF::getSingleton('encodingHandler', $config);
427
+ $params = $this->_getParamsParser()->getServerRequestParams();
428
+ $dataProvider = $this->_getDataProvider();
429
+ $dataProvider->setParam('idsOnly', 'true');
430
+ $this->_recommendationAdapter = FF::getSingleton('xml67/recommendationAdapter', $dataProvider, $this->_getParamsParser(), $encodingHandler);
431
+ }
432
+ return $this->_recommendationAdapter;
433
+ }
434
+
435
+ /**
436
+ * get Product Campaign Adapter
437
+ *
438
+ * @return FACTFinder_Abstract_ProductCampaignAdapter
439
+ */
440
+ public function getProductCampaignAdapter()
441
+ {
442
+ if ($this->_productCampaignAdapter == null) {
443
+ $config = $this->_getConfiguration();
444
+ $encodingHandler = FF::getSingleton('encodingHandler', $config);
445
+ $params = $this->_getParamsParser()->getServerRequestParams();
446
+ $dataProvider = $this->_getDataProvider();
447
+ $dataProvider->setParam('idsOnly', 'true');
448
+ $this->_productCampaignAdapter = FF::getSingleton('xml67/productCampaignAdapter', $dataProvider, $this->_getParamsParser(), $encodingHandler);
449
+ }
450
+ return $this->_productCampaignAdapter;
451
+ }
452
+
453
+ /**
454
+ * get Search Result Count
455
+ *
456
+ * @return int
457
+ */
458
+ public function getSearchResultCount()
459
+ {
460
+ $count = 0;
461
+ try {
462
+ $count = $this->_getSearchAdapter()->getResult()->getFoundRecordsCount();
463
+ }
464
+ catch (Exception $e) {
465
+ Mage::logException($e);
466
+ }
467
+
468
+ return $count;
469
+ }
470
+
471
+ /**
472
+ * get After Search Navigation as Array
473
+ * this simulates Magento Filter Attributes with Options
474
+ *
475
+ * @return array
476
+ */
477
+ public function getAfterSearchNavigation()
478
+ {
479
+ if($this->_afterSearchNavigation == null){
480
+ $this->_afterSearchNavigation = array();
481
+
482
+ $result = array();
483
+ try {
484
+ $result = $this->_getSearchAdapter()->getAsn();
485
+ }
486
+ catch (Exception $e) {
487
+ Mage::logException($e);
488
+ }
489
+
490
+
491
+ if ($result instanceof FACTFinder_Asn
492
+ && count($result)){
493
+
494
+ foreach ($result as $row) {
495
+ $this->_afterSearchNavigation[] = array(
496
+ 'attribute_code' => $row->getName(),
497
+ 'name' => $row->getName(),
498
+ 'unit' => $row->getUnit(),
499
+ 'items' => $this->_getAttributeOptions($row->getArrayCopy(), $row->getUnit()),
500
+ 'count' => $row->count(),
501
+ 'type' => $this->_getFilterType($row->getArrayCopy()),
502
+ 'store_label' => $row->getName()
503
+ );
504
+ }
505
+ }
506
+ }
507
+
508
+ return $this->_afterSearchNavigation;
509
+ }
510
+
511
+ /**
512
+ * get Filter Type by FACT-Finder FilterItem
513
+ *
514
+ * @param array $options
515
+ * @return string
516
+ */
517
+ protected function _getFilterType($options)
518
+ {
519
+ $defaultType = 'item';
520
+ foreach($options as $option){
521
+ if(!$option->getType()){
522
+ continue;
523
+ }
524
+ $defaultType = $option->getType();
525
+ break;
526
+ }
527
+ return $defaultType;
528
+ }
529
+
530
+ /**
531
+ * get Attribute Options Array from FactFinder FilterGroupItems
532
+ *
533
+ * @param FACTFinder_AsnFilterItem $options
534
+ * @return array
535
+ */
536
+ protected function _getAttributeOptions($options, $unit = '')
537
+ {
538
+ $attributeOption = array();
539
+ if (!empty($unit)) $unit = ' ' . $unit;
540
+ $_currentCategoryPath = $this->_getCurrentFactfinderCategoryPath(true);
541
+ $helper = Mage::helper('factfinder/search');
542
+ foreach($options as $option){
543
+
544
+ switch ($option->getType()){
545
+
546
+ case "slider":
547
+ $attributeOption[] = array(
548
+ 'type' => $option->getType(),
549
+ 'label' => 'slider',
550
+ 'value' => $this->_getAttributeOptionValue($option),
551
+ 'absolute_min' => $option->getAbsoluteMin(),
552
+ 'absolute_max' => $option->getAbsoluteMax(),
553
+ 'selected_min' => $option->getSelectedMin(),
554
+ 'selected_max' => $option->getSelectedMax(),
555
+ 'count' => true,
556
+ 'selected' => false //$option->isSelected()
557
+ );
558
+ break;
559
+
560
+ default:
561
+ if (!Mage::helper('core/string')->strlen($option->getValue())) {
562
+ continue;
563
+ }
564
+ // remove Categories from top Level Navigation
565
+ $_value = $this->_getAttributeOptionValue($option);
566
+ if(Mage::getStoreConfigFlag('factfinder/activation/navigation')
567
+ && !$helper->getIsOnSearchPage()
568
+ && (
569
+ empty($_value) === true
570
+ || in_array($_value, $_currentCategoryPath)
571
+ && $_currentCategoryPath[count($_currentCategoryPath)-1] != $_value
572
+ )){
573
+ continue;
574
+ }
575
+
576
+ $attributeOption[] = array(
577
+ 'type' => 'attribute',
578
+ 'label' => $option->getValue() . $unit,
579
+ 'value' => $_value,
580
+ 'count' => $option->getMatchCount(),
581
+ 'selected' => $option->isSelected(),
582
+ 'clusterLevel' => $option->getClusterLevel()
583
+ );
584
+ break;
585
+ }
586
+ }
587
+ return $attributeOption;
588
+ }
589
+
590
+ /**
591
+ * get current FACT-Finder Catgory Path
592
+ *
593
+ * @return string
594
+ */
595
+ protected function _getCurrentFactfinderCategoryPath($all = false)
596
+ {
597
+ $returnValue = '';
598
+ if($this->_currentFactfinderCategoryPath == null && Mage::getStoreConfigFlag('factfinder/activation/navigation') && Mage::registry('current_category')){
599
+ $this->_currentFactfinderCategoryPath = array();
600
+ /* @var $category Mage_Catalog_Model_Category */
601
+ $category = Mage::registry('current_category');
602
+
603
+ $pathInStore = $category->getPathInStore();
604
+ $pathIds = array_reverse(explode(',', $pathInStore));
605
+
606
+ $categories = $category->getParentCategories();
607
+ $mainCategoriesString = '';
608
+ foreach ($pathIds as $categoryId) {
609
+ if (isset($categories[$categoryId]) && $categories[$categoryId]->getName()) {
610
+ if(empty($mainCategoriesString)){
611
+ $this->_currentFactfinderCategoryPath[] = 'categoryROOT|'.$categories[$categoryId]->getName();
612
+ }else{
613
+ $this->_currentFactfinderCategoryPath[] = 'categoryROOT'.$mainCategoriesString.'|'.$categories[$categoryId]->getName();
614
+ }
615
+ $mainCategoriesString .= '/'. str_replace('/', '%2F', $categories[$categoryId]->getName());
616
+ }
617
+ }
618
+ } else {
619
+ $this->_currentFactfinderCategoryPath = array();
620
+ }
621
+
622
+ if($all === false){
623
+ if (isset($this->_currentFactfinderCategoryPath[count($this->_currentFactfinderCategoryPath)-1])) {
624
+ $returnValue = $this->_currentFactfinderCategoryPath[count($this->_currentFactfinderCategoryPath)-1];
625
+ }
626
+ else {
627
+ $returnValue = false;
628
+ }
629
+ } else {
630
+ $returnValue = $this->_currentFactfinderCategoryPath;
631
+ }
632
+
633
+ return $returnValue;
634
+ }
635
+
636
+ /**
637
+ * get Attribute option Value
638
+ *
639
+ * @param string $option
640
+ * @return string
641
+ */
642
+ protected function _getAttributeOptionValue($option)
643
+ {
644
+ $selectOptions = $this->_getSearchAdapter()->getSearchParams()->getFilters();
645
+ $value = null;
646
+ switch ($option->getType()) {
647
+
648
+ // handle Slider Attributes
649
+ case "slider";
650
+ $value = $option->getField().'|'.$option->getType().'|'.str_replace(array('&', '='), array('|', ':'), $option->getValue()).'[VALUE]';
651
+ break;
652
+
653
+ // handle default Attributes
654
+ default:
655
+ $value = $option->getField();
656
+ if($option->isSelected()){
657
+
658
+ // handle multiselectable Attributes
659
+ if(!empty($selectOptions[$option->getField()]) ){
660
+ if(strpos($option->getField(), 'categoryROOT') === false){
661
+ $values = explode('~~~', $selectOptions[$option->getField()]);
662
+ unset($values[array_search($option->getValue(), $values)]);
663
+ $value .= '|'.implode('~~~', $values);
664
+
665
+ }else{
666
+ $values = explode('/',str_replace('|'.$selectOptions[$option->getField()], '', $value));
667
+ $valueCount = count($values);
668
+ $value = '';
669
+ if($valueCount > 1){
670
+ for($i=0 ; $valueCount > $i ; $i++){
671
+ $value .= ($i != 0 ? ($i == $valueCount-1 ? '|' : '/') : '').$values[$i];
672
+ }
673
+ }
674
+ }
675
+ }
676
+ }else{
677
+ $value .= '|'.$option->getValue();
678
+ // handle multiselectable Attributes
679
+ if(!empty($selectOptions[$option->getField()])){
680
+ $value .= '~~~'.$selectOptions[$option->getField()];
681
+ }
682
+ }
683
+ break;
684
+ }
685
+ return $value;
686
+ }
687
+
688
+
689
+ /**
690
+ * get Search Result Product Ids and additional Data
691
+ *
692
+ * @return array Products Ids
693
+ */
694
+ public function getSearchResultProductIds()
695
+ {
696
+ if($this->_searchResultProductIds == null){
697
+ try {
698
+ $result = $this->_getSearchAdapter()->getResult();
699
+
700
+ $this->_searchResultProductIds = array();
701
+ if($result instanceof FACTFinder_Result){
702
+ foreach ($result AS $record){
703
+ if(isset($this->_searchResultProductIds[$record->getId()])){
704
+ continue;
705
+ }
706
+ $this->_searchResultProductIds[$record->getId()] = new Varien_Object(
707
+ array(
708
+ 'similarity' => $record->getSimilarity(),
709
+ 'position' => $record->getPosition(),
710
+ 'original_position' => $record->getOriginalPosition()
711
+ )
712
+ );
713
+ }
714
+ }
715
+ }
716
+ catch (Exception $e) {
717
+ Mage::logException($e);
718
+ $this->_searchResultProductIds = array();
719
+ }
720
+ }
721
+
722
+ return $this->_searchResultProductIds;
723
+ }
724
+
725
+ /**
726
+ * set single parameter, which will be looped through to the FACT-Finder request
727
+ *
728
+ * @param string name
729
+ * @param string value
730
+ */
731
+ protected function _setParam($name, $value, $log = true)
732
+ {
733
+ if($log){
734
+ Mage::helper('factfinder/debug')->log('set Param:'.$name.' => '.$value);
735
+ }
736
+ $this->_getDataProvider()->setParam($name, $value);
737
+ return $this;
738
+ }
739
+
740
+ /**
741
+ * get FactFinder DataProvider
742
+ *
743
+ * @return FACTFinder_Abstract_DataProvider
744
+ */
745
+ protected function _getDataProvider()
746
+ {
747
+ if ($this->_dataProvider == null) {
748
+ $config = $this->_getConfiguration();
749
+ $params = $this->_getParamsParser()->getServerRequestParams();
750
+
751
+ $this->_dataProvider = FF::getInstance('http/dataProvider', $params, $config);
752
+ }
753
+ return $this->_dataProvider;
754
+ }
755
+
756
+ /**
757
+ * get Autentivation URL
758
+ *
759
+ * @return string
760
+ */
761
+ public function getAuthenticationUrl()
762
+ {
763
+ $dataprovider = $this->_getDataProvider();
764
+ $dataprovider->setType('Management.ff');
765
+ return $dataprovider->getNonAuthenticationUrl();
766
+ }
767
+
768
+ /**
769
+ * get FactFinder Params Parser
770
+ *
771
+ * @return FACTFinder_ParametersParser
772
+ */
773
+ protected function _getParamsParser()
774
+ {
775
+ if ($this->_paramsParser == null) {
776
+ $config = $this->_getConfiguration();
777
+ $encodingHandler = FF::getSingleton('encodingHandler', $config);
778
+ $this->_paramsParser = FF::getInstance('parametersParser', $config, $encodingHandler);
779
+ }
780
+ return $this->_paramsParser;
781
+ }
782
+
783
+ /**
784
+ * set FactFinder Configuration
785
+ *
786
+ * @param array $configarray
787
+ */
788
+ public function setConfiguration($configarray)
789
+ {
790
+ $this->_config = FF::getSingleton('configuration', $configarray);
791
+ }
792
+
793
+ /**
794
+ * get FactFinder Configuration
795
+ *
796
+ * @return FACTFinder_Abstract_Configuration config
797
+ */
798
+ protected function _getConfiguration($configarray = null)
799
+ {
800
+ if ($this->_config == null) {
801
+ $this->_config = FF::getSingleton('configuration', $configarray);
802
+ }
803
+ return $this->_config;
804
+ }
805
+
806
+
807
+ /**
808
+ * Set StoreId for current configuration
809
+ *
810
+ * @param unknown_type $storeId
811
+ */
812
+ public function setStoreId($storeId) {
813
+ $this->_getConfiguration()->setStoreId($storeId);
814
+
815
+ return $this;
816
+ }
817
+ }
app/code/community/Flagbit/FactFinder/Model/Export/Price.php ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Model class
12
+ *
13
+ * This helper class provides the Price export
14
+ *
15
+ * @category Mage
16
+ * @package Flagbit_FactFinder
17
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
18
+ * @author Joerg Weller <weller@flagbit.de>
19
+ * @version $Id$
20
+ */
21
+ class Flagbit_FactFinder_Model_Export_Price extends Mage_Core_Model_Mysql4_Abstract {
22
+
23
+ /**
24
+ * defines Export Columns
25
+ * @var array
26
+ */
27
+ protected $_exportColumns = array('entity_id', 'customer_group_id', 'final_price', 'min_price');
28
+
29
+ /**
30
+ * Resource initialization
31
+ */
32
+ protected function _construct(){
33
+ $this->_setResource('core');
34
+ }
35
+
36
+ /**
37
+ * add CSV Row
38
+ *
39
+ * @param array $data
40
+ */
41
+ protected function _addCsvRow($data)
42
+ {
43
+ foreach($data as &$item){
44
+ $item = str_replace(array("\r", "\n", "\""), ' ', addcslashes(strip_tags($item), '"'));
45
+ }
46
+
47
+ echo '"'.implode('";"', $data).'"'."\n";
48
+ }
49
+
50
+ /**
51
+ * export Product Prices
52
+ * direct Output as CSV
53
+ *
54
+ * @param int $storeId Store View Id
55
+ */
56
+ public function doExport($storeId = null)
57
+ {
58
+ $this->_addCsvRow($this->_exportColumns);
59
+ for($i=1; $prices = $this->_getPrices($storeId, $i); $i++){
60
+ foreach($prices as $price){
61
+ $this->_addCsvRow($price);
62
+ }
63
+ }
64
+ }
65
+
66
+ /**
67
+ * get Prices from Price Index Table
68
+ *
69
+ * @param int $storeId Store ID
70
+ * @param int $part
71
+ * @param int $limit
72
+ * @return array
73
+ */
74
+ protected function _getPrices($storeId, $part = 1, $limit = 100){
75
+
76
+ $store = Mage::app()->getStore($storeId);
77
+ $select = $this->_getWriteAdapter()->select()
78
+ ->from(
79
+ array('e' => $this->getTable('catalog/product_index_price')),
80
+ $this->_exportColumns);
81
+
82
+ if($storeId !== null){
83
+ $select->where('e.website_id = ?', $store->getWebsiteId());
84
+ }
85
+
86
+ $select->limitPage($part, $limit)
87
+ ->order('e.entity_id');
88
+
89
+ return $this->_getWriteAdapter()->fetchAll($select);
90
+ }
91
+ }
app/code/community/Flagbit/FactFinder/Model/Export/Product.php ADDED
@@ -0,0 +1,535 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Model class
12
+ *
13
+ * This helper class provides the Product export
14
+ *
15
+ * @category Mage
16
+ * @package Flagbit_FactFinder
17
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
18
+ * @author Joerg Weller <weller@flagbit.de>
19
+ * @version $Id$
20
+ */
21
+ class Flagbit_FactFinder_Model_Export_Product extends Mage_CatalogSearch_Model_Mysql4_Fulltext {
22
+
23
+ /**
24
+ * Option ID to Value Mapping Array
25
+ * @var mixed
26
+ */
27
+ protected $_optionIdToValue = null;
28
+
29
+ /**
30
+ * Products to Category Path Mapping
31
+ *
32
+ * @var mixed
33
+ */
34
+ protected $_productsToCategoryPath = null;
35
+
36
+ /**
37
+ * Category Names by ID
38
+ * @var mixed
39
+ */
40
+ protected $_categoryNames = null;
41
+
42
+ /**
43
+ * export attribute codes
44
+ * @var mixed
45
+ */
46
+ protected $_exportAttributeCodes = null;
47
+
48
+ /**
49
+ * export attribute objects
50
+ * @var mixed
51
+ */
52
+ protected $_exportAttributes = null;
53
+
54
+ /**
55
+ * helper to generate the image urls
56
+ * @var Mage_Catalog_Helper_Image
57
+ */
58
+ protected $_imageHelper = null;
59
+
60
+ /**
61
+ * add CSV Row
62
+ *
63
+ * @param array $data
64
+ */
65
+ protected function _addCsvRow($data)
66
+ {
67
+ foreach ($data as &$item) {
68
+ $item = str_replace(array("\r", "\n", "\""), array(' ', ' ', "''"), trim( strip_tags($item), ';') );
69
+ }
70
+
71
+ echo '"'.implode('";"', $data).'"'."\n";
72
+ }
73
+
74
+ /**
75
+ * get Option Text by Option ID
76
+ *
77
+ * @param int $optionId Option ID
78
+ * @param int $storeId Store ID
79
+ * @return string
80
+ */
81
+ protected function _getAttributeOptionText($optionId, $storeId)
82
+ {
83
+ $value = '';
84
+ if (intval($optionId)) {
85
+ if ($this->_optionIdToValue === null) {
86
+ /*@var $optionCollection Mage_Eav_Model_Mysql4_Entity_Attribute_Option_Collection */
87
+ $optionCollection = Mage::getResourceModel('eav/entity_attribute_option_collection');
88
+ $optionCollection->setStoreFilter($storeId);
89
+ $this->_optionIdToValue = array();
90
+ foreach ($optionCollection as $option) {
91
+ $this->_optionIdToValue[$option->getId()] = $option->getValue();
92
+ }
93
+ }
94
+ $value = isset($this->_optionIdToValue[$optionId]) ? $this->_optionIdToValue[$optionId] : '';
95
+ }
96
+ return $value;
97
+ }
98
+
99
+ /**
100
+ * get CSV Header Array
101
+ *
102
+ * @param int $storeId
103
+ * @return array
104
+ */
105
+ protected function _getExportAttributes($storeId = null)
106
+ {
107
+ if($this->_exportAttributeCodes === null){
108
+ $headerDefault = array('id', 'parent_id', 'sku', 'category', 'filterable_attributes', 'searchable_attributes');
109
+ $headerDynamic = array();
110
+
111
+ if (Mage::getStoreConfigFlag('factfinder/export/urls', $storeId)) {
112
+ $headerDefault[] = 'image';
113
+ $headerDefault[] = 'deeplink';
114
+ $this->_imageHelper = Mage::helper('catalog/image');
115
+ }
116
+
117
+ // get dynamic Attributes
118
+ foreach ($this->_getSearchableAttributes(null, 'system', $storeId) as $attribute) {
119
+ if (in_array($attribute->getAttributeCode(), array('sku', 'status', 'visibility'))) {
120
+ continue;
121
+ }
122
+ $headerDynamic[] = $attribute->getAttributeCode();
123
+ }
124
+
125
+ // compare dynamic with setup attributes
126
+ $headerSetup = Mage::helper('factfinder/backend')->makeArrayFieldValue(Mage::getStoreConfig('factfinder/export/attributes', $storeId));
127
+ $setupUpdate = false;
128
+ foreach($headerDynamic as $code){
129
+ if(in_array($code, $headerSetup)){
130
+ continue;
131
+ }
132
+ $headerSetup[$code]['attribute'] = $code;
133
+ $setupUpdate = true;
134
+ }
135
+ if($setupUpdate === true){
136
+ Mage::getModel('core/config')->saveConfig('factfinder/export/attributes', Mage::helper('factfinder/backend')->makeStorableArrayFieldValue($headerSetup), 'stores', $storeId);
137
+ }
138
+
139
+ $this->_exportAttributeCodes = array_merge($headerDefault, array_keys($headerSetup));
140
+ }
141
+ return $this->_exportAttributeCodes;
142
+ }
143
+
144
+
145
+ /**
146
+ * export Product Data with Attributes
147
+ * direct Output as CSV
148
+ *
149
+ * @param int $storeId Store View Id
150
+ */
151
+ public function doExport($storeId = null)
152
+ {
153
+ $idFieldName = Mage::helper('factfinder/search')->getIdFieldName();
154
+ $exportImageAndDeeplink = Mage::getStoreConfigFlag('factfinder/export/urls', $storeId);
155
+
156
+ $header = $this->_getExportAttributes($storeId);
157
+ $this->_addCsvRow($header);
158
+
159
+ // preparesearchable attributes
160
+ $staticFields = array();
161
+ foreach ($this->_getSearchableAttributes('static', 'system', $storeId) as $attribute) {
162
+ $staticFields[] = $attribute->getAttributeCode();
163
+ }
164
+ $dynamicFields = array(
165
+ 'int' => array_keys($this->_getSearchableAttributes('int')),
166
+ 'varchar' => array_keys($this->_getSearchableAttributes('varchar')),
167
+ 'text' => array_keys($this->_getSearchableAttributes('text')),
168
+ 'decimal' => array_keys($this->_getSearchableAttributes('decimal')),
169
+ 'datetime' => array_keys($this->_getSearchableAttributes('datetime')),
170
+ );
171
+
172
+ // status and visibility filter
173
+ $visibility = $this->_getSearchableAttribute('visibility');
174
+ $status = $this->_getSearchableAttribute('status');
175
+ $visibilityVals = Mage::getSingleton('catalog/product_visibility')->getVisibleInSearchIds();
176
+ $statusVals = Mage::getSingleton('catalog/product_status')->getVisibleStatusIds();
177
+
178
+ $lastProductId = 0;
179
+ while (true) {
180
+ $products = $this->_getSearchableProducts($storeId, $staticFields, null, $lastProductId);
181
+ if (!$products) {
182
+ break;
183
+ }
184
+
185
+ $productRelations = array();
186
+ foreach ($products as $productData) {
187
+ $lastProductId = $productData['entity_id'];
188
+ $productAttributes[$productData['entity_id']] = $productData['entity_id'];
189
+ $productChilds = $this->_getProductChildIds($productData['entity_id'], $productData['type_id']);
190
+ $productRelations[$productData['entity_id']] = $productChilds;
191
+ if ($productChilds) {
192
+ foreach ($productChilds as $productChild) {
193
+ $productAttributes[$productChild['entity_id']] = $productChild;
194
+ }
195
+ }
196
+ }
197
+
198
+ $productIndexes = array();
199
+ $productAttributes = $this->_getProductAttributes($storeId, $productAttributes, $dynamicFields);
200
+ foreach ($products as $productData) {
201
+ if (!isset($productAttributes[$productData['entity_id']])) {
202
+ continue;
203
+ }
204
+ $protductAttr = $productAttributes[$productData['entity_id']];
205
+
206
+ if (!isset($protductAttr[$visibility->getId()]) || !in_array($protductAttr[$visibility->getId()], $visibilityVals)) {
207
+ continue;
208
+ }
209
+ if (!isset($protductAttr[$status->getId()]) || !in_array($protductAttr[$status->getId()], $statusVals)) {
210
+ continue;
211
+ }
212
+
213
+ $productIndex = array(
214
+ $productData['entity_id'],
215
+ $productData[$idFieldName],
216
+ $productData['sku'],
217
+ $this->_getCategoryPath($productData['entity_id'], $storeId),
218
+ $this->_formatFilterableAttributes($this->_getSearchableAttributes(null, 'filterable'), $protductAttr, $storeId),
219
+ $this->_formatSearchableAttributes($this->_getSearchableAttributes(null, 'searchable'), $protductAttr, $storeId)
220
+ );
221
+
222
+ if ($exportImageAndDeeplink) {
223
+ $product = Mage::getModel("catalog/product");
224
+ $product->load($productData['entity_id']);
225
+
226
+ $productIndex[] = $this->_imageHelper->init($product, 'image')->resize(120)->__toString();
227
+ $productIndex[] = $product->getProductUrl();
228
+ }
229
+
230
+ $this->_getAttributesRowArray($productIndex, $protductAttr, $storeId);
231
+
232
+ $this->_addCsvRow($productIndex);
233
+
234
+ if ($productChilds = $productRelations[$productData['entity_id']]) {
235
+ foreach ($productChilds as $productChild) {
236
+ if (isset($productAttributes[$productChild['entity_id']])) {
237
+
238
+ $subProductIndex = array(
239
+ $productChild['entity_id'],
240
+ $productData[$idFieldName],
241
+ $productChild['sku'],
242
+ $this->_getCategoryPath($productData['entity_id'], $storeId),
243
+ $this->_formatFilterableAttributes($this->_getSearchableAttributes(null, 'filterable'), $productAttributes[$productChild['entity_id']], $storeId),
244
+ $this->_formatSearchableAttributes($this->_getSearchableAttributes(null, 'searchable'), $productAttributes[$productChild['entity_id']], $storeId)
245
+ );
246
+ if ($exportImageAndDeeplink) {
247
+ //dont need to add image and deeplink to child product, just add empty values
248
+ $subProductIndex[] = '';
249
+ $subProductIndex[] = '';
250
+ }
251
+ $this->_getAttributesRowArray($subProductIndex, $productAttributes[$productChild['entity_id']], $storeId);
252
+
253
+ $this->_addCsvRow($subProductIndex);
254
+ }
255
+ }
256
+ }
257
+ }
258
+ flush();
259
+ }
260
+ }
261
+
262
+ protected function _formatSearchableAttributes($attributes, $values, $storeId=null)
263
+ {
264
+ $returnArray = array();
265
+ foreach ($attributes as $attribute) {
266
+ $value = isset($values[$attribute->getId()]) ? $values[$attribute->getId()] : null;
267
+ if (!$value || in_array($attribute->getAttributeCode(), array('sku', 'status', 'visibility', 'price'))) {
268
+ continue;
269
+ }
270
+ $attributeValue = $this->_getAttributeValue($attribute->getId(), $value, $storeId);
271
+ if (strval($attributeValue) != "") {
272
+ $returnArray[] = $attributeValue;
273
+ }
274
+ }
275
+ return implode(',', $returnArray);
276
+ }
277
+
278
+ protected function _formatFilterableAttributes($attributes, $values, $storeId=null)
279
+ {
280
+ $returnArray = array();
281
+ foreach ($attributes as $attribute) {
282
+ $value = isset($values[$attribute->getId()]) ? $values[$attribute->getId()] : null;
283
+ if (!$value || in_array($attribute->getAttributeCode(), array('sku', 'status', 'visibility', 'price'))) {
284
+ continue;
285
+ }
286
+ $attributeValue = $this->_getAttributeValue($attribute->getId(), $value, $storeId);
287
+ $attributeValues = array();
288
+ if (strpos($attributeValue, '|') !== false) {
289
+ $attributeValues = explode('|', $attributeValue);
290
+ } else {
291
+ $attributeValues[] = $attributeValue;
292
+ }
293
+
294
+ foreach ($attributeValues AS $value) {
295
+ if (strval($value) != "") {
296
+ $returnArray[] = $attribute->getAttributeCode().'='.$value;
297
+ }
298
+ }
299
+ }
300
+ return implode('|', $returnArray);
301
+ }
302
+
303
+ /**
304
+ * Retrieve Searchable attributes
305
+ *
306
+ * @param string $backendType
307
+ * @param string $type possible Types: system, sortable, filterable, searchable
308
+ * @return array
309
+ */
310
+ protected function _getSearchableAttributes($backendType = null, $type = null, $storeId = null)
311
+ {
312
+ if (is_null($this->_searchableAttributes)) {
313
+ $this->_searchableAttributes = array();
314
+ $entityType = $this->getEavConfig()->getEntityType('catalog_product');
315
+ $entity = $entityType->getEntity();
316
+
317
+ $userDefinedAttributes = array_keys(Mage::helper('factfinder/backend')->makeArrayFieldValue(Mage::getStoreConfig('factfinder/export/attributes', $storeId)));
318
+
319
+ $whereCond = array(
320
+ $this->_getWriteAdapter()->quoteInto('additional_table.is_searchable=? or additional_table.is_filterable=? or additional_table.used_for_sort_by=?', 1),
321
+ $this->_getWriteAdapter()->quoteInto('main_table.attribute_code IN(?)', array_merge(array('status', 'visibility'), $userDefinedAttributes))
322
+ );
323
+
324
+ $select = $this->_getWriteAdapter()->select()
325
+ ->from(array('main_table' => $this->getTable('eav/attribute')))
326
+ ->join(
327
+ array('additional_table' => $this->getTable('catalog/eav_attribute')),
328
+ 'additional_table.attribute_id = main_table.attribute_id'
329
+ )
330
+ ->where('main_table.entity_type_id=?', $entityType->getEntityTypeId())
331
+ ->where(join(' OR ', $whereCond))
332
+ ->order('main_table.attribute_id', 'asc');
333
+
334
+ $attributesData = $this->_getWriteAdapter()->fetchAll($select);
335
+ $this->getEavConfig()->importAttributesData($entityType, $attributesData);
336
+ foreach ($attributesData as $attributeData) {
337
+ $attributeCode = $attributeData['attribute_code'];
338
+ $attribute = $this->getEavConfig()->getAttribute($entityType, $attributeCode);
339
+ $attribute->setEntity($entity);
340
+ $this->_searchableAttributes[$attribute->getId()] = $attribute;
341
+ }
342
+ unset($attributesData);
343
+ }
344
+
345
+ if (!is_null($type) || !is_null($backendType)) {
346
+ $attributes = array();
347
+ foreach ($this->_searchableAttributes as $attribute) {
348
+
349
+ if (!is_null($backendType)
350
+ && $attribute->getBackendType() != $backendType) {
351
+ continue;
352
+ }
353
+
354
+ switch($type) {
355
+
356
+ case "system":
357
+ if ($attribute->getIsUserDefined()
358
+ && !$attribute->getUsedForSortBy()) {
359
+ continue 2;
360
+ }
361
+ break;
362
+
363
+ case "sortable":
364
+ if (!$attribute->getUsedForSortBy()) {
365
+ continue 2;
366
+ }
367
+ break;
368
+
369
+ case "filterable":
370
+ if (!$attribute->getIsFilterableInSearch()
371
+ || in_array($attribute->getAttributeCode(), $this->_getExportAttributes())) {
372
+ continue 2;
373
+ }
374
+ break;
375
+
376
+ case "searchable":
377
+ if (!$attribute->getIsUserDefined()
378
+ || !$attribute->getIsSearchable()
379
+ || in_array($attribute->getAttributeCode(), $this->_getExportAttributes())) {
380
+ continue 2;
381
+ }
382
+ break;
383
+ }
384
+
385
+ $attributes[$attribute->getId()] = $attribute;
386
+ }
387
+ return $attributes;
388
+ }
389
+ return $this->_searchableAttributes;
390
+ }
391
+
392
+ /**
393
+ * Get Category Path by Product ID
394
+ *
395
+ * @param int $productId
396
+ * @param int $storeId
397
+ * @return string
398
+ */
399
+ protected function _getCategoryPath($productId, $storeId = null)
400
+ {
401
+
402
+ if ($this->_categoryNames === null) {
403
+ $categoryCollection = Mage::getResourceModel('catalog/category_attribute_collection');
404
+ $categoryCollection->getSelect()->where("attribute_code IN('name', 'is_active')");
405
+
406
+ foreach ($categoryCollection as $categoryModel) {
407
+ ${$categoryModel->getAttributeCode().'Model'} = $categoryModel;
408
+ }
409
+
410
+ $select = $this->_getReadAdapter()->select()
411
+ ->from(
412
+ array('main' => $nameModel->getBackendTable()),
413
+ array('entity_id', 'value')
414
+ )
415
+ ->join(
416
+ array('e' => $is_activeModel->getBackendTable()),
417
+ 'main.entity_id=e.entity_id AND (e.store_id = 0 OR e.store_id = '.$storeId.') AND e.attribute_id='.$is_activeModel->getAttributeId(),
418
+ null
419
+ )
420
+ ->where('main.attribute_id=?', $nameModel->getAttributeId())
421
+ ->where('e.value=?', '1')
422
+ ->where('main.store_id = 0 OR main.store_id = ?', $storeId);
423
+
424
+ $this->_categoryNames = $this->_getReadAdapter()->fetchPairs($select);
425
+ }
426
+
427
+ if ($this->_productsToCategoryPath === null) {
428
+ $select = $this->_getReadAdapter()->select()
429
+ ->from(
430
+ array('main' => $this->getTable('catalog/category_product_index')),
431
+ array('product_id')
432
+ )
433
+ ->join(
434
+ array('e' => $this->getTable('catalog/category')),
435
+ 'main.category_id=e.entity_id',
436
+ null
437
+ )
438
+ ->columns(array('e.path' => new Zend_Db_Expr('GROUP_CONCAT(e.path)')))
439
+ ->where('main.visibility IN(3,4)') //TODO look for Constants
440
+ ->where('main.store_id = ?', $storeId)
441
+ ->where('e.path LIKE \'1/' . Mage::app()->getStore()->getRootCategoryId() .'/%\'')
442
+ ->group('main.product_id');
443
+
444
+ $this->_productsToCategoryPath = $this->_getReadAdapter()->fetchPairs($select);
445
+ }
446
+
447
+ $value = '';
448
+ if (isset($this->_productsToCategoryPath[$productId])) {
449
+ $paths = explode(',', $this->_productsToCategoryPath[$productId]);
450
+ foreach ($paths as $path) {
451
+ $categoryIds = explode('/', $path);
452
+ $categoryIdsCount = count($categoryIds);
453
+ $categoryPath = '';
454
+ for($i=2;$i < $categoryIdsCount;$i++) {
455
+ if (!isset($this->_categoryNames[$categoryIds[$i]])) {
456
+ continue 2;
457
+ }
458
+ $categoryPath .= urlencode($this->_categoryNames[$categoryIds[$i]]).'/';
459
+ }
460
+ if ($categoryIdsCount > 2) {
461
+ $value .= rtrim($categoryPath,'/').'|';
462
+ }
463
+ }
464
+ $value = trim($value, '|');
465
+ }
466
+
467
+ return $value;
468
+ }
469
+
470
+ /**
471
+ * Return all product children ids
472
+ *
473
+ * @param int $productId Product Entity Id
474
+ * @param string $typeId Super Product Link Type
475
+ * @return array
476
+ */
477
+ protected function _getProductChildIds($productId, $typeId)
478
+ {
479
+ $typeInstance = $this->_getProductTypeInstance($typeId);
480
+ $relation = $typeInstance->isComposite()
481
+ ? $typeInstance->getRelationInfo()
482
+ : false;
483
+
484
+ if ($relation && $relation->getTable() && $relation->getParentFieldName() && $relation->getChildFieldName()) {
485
+ $select = $this->_getReadAdapter()->select()
486
+ ->from(
487
+ array('main' => $this->getTable($relation->getTable())),
488
+ array($relation->getChildFieldName()))
489
+
490
+ ->join(
491
+ array('e' => $this->getTable('catalog/product')),
492
+ 'main.'.$relation->getChildFieldName().'=e.entity_id',
493
+ array('entity_id', 'type_id', 'sku')
494
+ )
495
+
496
+ ->where("{$relation->getParentFieldName()}=?", $productId);
497
+ if (!is_null($relation->getWhere())) {
498
+ $select->where($relation->getWhere());
499
+ }
500
+ return $this->_getReadAdapter()->fetchAll($select);
501
+ }
502
+
503
+ return null;
504
+ }
505
+
506
+ /**
507
+ * get Attribute Row Array
508
+ *
509
+ * @param array $dataArray Export row Array
510
+ * @param array $attributes Attributes Array
511
+ * @param int $storeId Store ID
512
+ */
513
+ protected function _getAttributesRowArray(&$dataArray, $values, $storeId=null)
514
+ {
515
+ // get attributes objects assigned to their position at the export
516
+ if ($this->_exportAttributes == null) {
517
+ $this->_exportAttributes = array_fill(0, sizeof($this->_getExportAttributes()), null);
518
+
519
+ $attributeCodes = array_flip($this->_getExportAttributes());
520
+ foreach ($this->_getSearchableAttributes() as $attribute) {
521
+ if (isset($attributeCodes[$attribute->getAttributeCode()]) && !in_array($attribute->getAttributeCode(), array('sku', 'status', 'visibility'))) {
522
+ $this->_exportAttributes[$attributeCodes[$attribute->getAttributeCode()]] = $attribute;
523
+ }
524
+ }
525
+ }
526
+
527
+ // fill dataArray with the values of the attributes that should be exported
528
+ foreach($this->_exportAttributes AS $pos => $attribute) {
529
+ if ($attribute != null) {
530
+ $value = isset($values[$attribute->getId()]) ? $values[$attribute->getId()] : null;
531
+ $dataArray[$pos] = $this->_getAttributeValue($attribute->getId(), $value, $storeId);
532
+ }
533
+ }
534
+ }
535
+ }
app/code/community/Flagbit/FactFinder/Model/Export/Stock.php ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Model class
12
+ *
13
+ * This helper class provides the Stock export
14
+ *
15
+ * @category Mage
16
+ * @package Flagbit_FactFinder
17
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
18
+ * @author Joerg Weller <weller@flagbit.de>
19
+ * @version $Id$
20
+ */
21
+ class Flagbit_FactFinder_Model_Export_Stock extends Mage_Core_Model_Mysql4_Abstract {
22
+
23
+ /**
24
+ * defines Export Columns
25
+ * @var array
26
+ */
27
+ protected $_exportColumns = array('product_id', 'qty', 'stock_status');
28
+
29
+ /**
30
+ * Resource initialization
31
+ */
32
+ protected function _construct(){
33
+ $this->_setResource('core');
34
+ }
35
+
36
+ /**
37
+ * add CSV Row
38
+ *
39
+ * @param array $data
40
+ */
41
+ protected function _addCsvRow($data)
42
+ {
43
+ foreach($data as &$item){
44
+ $item = str_replace(array("\r", "\n", "\""), ' ', addcslashes(strip_tags($item), '"'));
45
+ }
46
+
47
+ echo '"'.implode('";"', $data).'"'."\n";
48
+ }
49
+
50
+ /**
51
+ * export Stock Data
52
+ * direct Output as CSV
53
+ *
54
+ * @param int $storeId Store Id
55
+ */
56
+ public function doExport($storeId = null)
57
+ {
58
+ $this->_addCsvRow($this->_exportColumns);
59
+ for($i=1; $stocks = $this->_getStockData($storeId, $i); $i++){
60
+ foreach($stocks as $stock){
61
+ $this->_addCsvRow($stock);
62
+ }
63
+ }
64
+ }
65
+
66
+ /**
67
+ * get Stocks from Stock Index Table
68
+ *
69
+ * @param int $storeId Store ID
70
+ * @param int $part
71
+ * @param int $limit
72
+ * @return array
73
+ */
74
+ protected function _getStockData($storeId, $part = 1, $limit = 100){
75
+
76
+ $store = Mage::app()->getStore($storeId);
77
+ $select = $this->_getWriteAdapter()->select()
78
+ ->from(
79
+ array('e' => $this->getTable('cataloginventory/stock_status')),
80
+ $this->_exportColumns);
81
+
82
+ if($storeId !== null){
83
+ $select->where('e.website_id = ?', $store->getWebsiteId());
84
+ }
85
+
86
+ $select->limitPage($part, $limit)
87
+ ->order('e.product_id');
88
+
89
+ return $this->_getWriteAdapter()->fetchAll($select);
90
+ }
91
+ }
app/code/community/Flagbit/FactFinder/Model/Layer.php ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Block class for upselling
12
+ *
13
+ * Rewritten block - data is now caught by FACT-Finder, passed to normal collection, works quite as if it was the
14
+ * default behavior.
15
+ *
16
+ * @category Mage
17
+ * @package Flagbit_FactFinder
18
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
19
+ * @author Jörg Weller <weller@flagbit.de>
20
+ * @version $Id$
21
+ */
22
+ class Flagbit_FactFinder_Model_Layer extends Flagbit_FactFinder_Model_Layer_Abstract
23
+ {
24
+ const XML_PATH_DISPLAY_LAYER_COUNT = 'catalog/search/use_layered_navigation_count';
25
+
26
+ protected $_productCollection = null;
27
+
28
+ /**
29
+ * Get current layer product collection
30
+ *
31
+ * @return Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection
32
+ */
33
+ public function getProductCollection()
34
+ {
35
+ if(!Mage::helper('factfinder/search')->getIsEnabled()){
36
+ return parent::getProductCollection();
37
+ }
38
+
39
+ // handle search
40
+ if($this instanceof Mage_CatalogSearch_Model_Layer){
41
+ if(is_null($this->_productCollection)){
42
+ $this->_productCollection = Mage::getResourceModel('factfinder/search_collection');
43
+ $this->prepareProductCollection($this->_productCollection);
44
+ }
45
+ $collection = $this->_productCollection;
46
+
47
+ // handle category listing
48
+ }else{
49
+ if (isset($this->_productCollections[$this->getCurrentCategory()->getId()])) {
50
+ $collection = $this->_productCollections[$this->getCurrentCategory()->getId()];
51
+ }
52
+ else {
53
+ //$collection = $this->getCurrentCategory();
54
+ $collection = Mage::getResourceModel('factfinder/search_collection');
55
+ $this->prepareProductCollection($collection);
56
+ $this->_productCollections[$this->getCurrentCategory()->getId()] = $collection;
57
+ }
58
+ }
59
+
60
+
61
+ return $collection;
62
+ }
63
+
64
+ /**
65
+ * Get collection of all filterable attributes for layer products set
66
+ *
67
+ * @return Flagbit_FactFinder_Model_Mysql4_Product_Attribute_Collection
68
+ */
69
+ public function getFilterableAttributes()
70
+ {
71
+
72
+ if(!Mage::helper('factfinder/search')->getIsEnabled(false, 'asn')){
73
+ return parent::getFilterableAttributes();
74
+ }
75
+
76
+ /* @var $collection Flagbit_FactFinder_Model_Mysql4_Product_Attribute_Collection */
77
+ $collection = Mage::getResourceModel('factfinder/product_attribute_collection')
78
+ ->setItemObjectClass('catalog/resource_eav_attribute')
79
+ ->setStoreId(Mage::app()->getStore()->getId());
80
+
81
+ return $collection;
82
+ }
83
+ }
app/code/community/Flagbit/FactFinder/Model/Layer/Abstract.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if(Mage::helper('factfinder/search')->getIsOnSearchPage()){
4
+ class Flagbit_FactFinder_Model_Layer_Abstract extends Mage_CatalogSearch_Model_Layer {}
5
+ }else{
6
+ class Flagbit_FactFinder_Model_Layer_Abstract extends Mage_Catalog_Model_Layer {}
7
+ }
app/code/community/Flagbit/FactFinder/Model/Layer/Filter/Attribute/Abstract.php ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Model class
12
+ *
13
+ * This helper class provides the Price export
14
+ *
15
+ * @category Mage
16
+ * @package Flagbit_FactFinder
17
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
18
+ * @author Joerg Weller <weller@flagbit.de>
19
+ * @version $Id$
20
+ */
21
+ class Flagbit_FactFinder_Model_Layer_Filter_Attribute_Abstract extends Mage_Catalog_Model_Layer_Filter_Attribute {
22
+
23
+ /**
24
+ * Array of Magento Layer Filter Items
25
+ * @var mixed
26
+ */
27
+ protected $_filterItems = null;
28
+
29
+ /**
30
+ * Array of Selected Layer Filters
31
+ * @var mixed
32
+ */
33
+ protected $_selectedFilterItems = array();
34
+
35
+ /**
36
+ * Apply attribute option filter to product collection
37
+ *
38
+ * @param Zend_Controller_Request_Abstract $request
39
+ * @param Varien_Object $filterBlock
40
+ * @return Mage_Catalog_Model_Layer_Filter_Attribute
41
+ */
42
+ public function apply(Zend_Controller_Request_Abstract $request, $filterBlock)
43
+ {
44
+ if(!Mage::helper('factfinder/search')->getIsEnabled(false, 'asn')){
45
+ return parent::apply($request, $filterBlock);
46
+ }
47
+ $this->_getItemsData();
48
+ $_attributeCode = $filterBlock->getAttributeModel()->getAttributeCode();
49
+ if (isset($this->_selectedFilterItems[$_attributeCode])
50
+ && is_array($this->_selectedFilterItems[$_attributeCode])) {
51
+
52
+ foreach($this->_selectedFilterItems[$_attributeCode] as $option){
53
+ $this->getLayer()->getState()->addFilter($this->_createItem($option['label'], $option['value']));
54
+ }
55
+ }
56
+ return $this;
57
+ }
58
+
59
+ /**
60
+ * Create filter item object
61
+ *
62
+ * @param string $label
63
+ * @param mixed $value
64
+ * @param int $count
65
+ * @return Mage_Catalog_Model_Layer_Filter_Item
66
+ */
67
+ protected function _createItem($label, $value, $count=0)
68
+ {
69
+
70
+ if (!Mage::helper('factfinder/search')->getIsEnabled(false, 'asn')) {
71
+ return parent::_createItem($label, $value, $count);
72
+ }
73
+
74
+ return Mage::getModel('factfinder/layer_filter_item')
75
+ ->setFilter($this)
76
+ ->setLabel($label)
77
+ ->setValue($value)
78
+ ->setCount($count);
79
+ }
80
+
81
+
82
+ /**
83
+ * Get data array for building attribute filter items
84
+ *
85
+ * @return array
86
+ */
87
+ protected function _getItemsData()
88
+ {
89
+ if(!Mage::helper('factfinder/search')->getIsEnabled(false, 'asn')){
90
+ return parent::_getItemsData();
91
+ }
92
+
93
+ if($this->_filterItems === null){
94
+ $attribute = $this->getAttributeModel();
95
+ $this->_requestVar = $attribute->getAttributeCode();
96
+
97
+ $key = $this->getLayer()->getStateKey().'_'.$this->_requestVar;
98
+ $data = $this->getLayer()->getAggregator()->getCacheData($key);
99
+
100
+ $options = $attribute->getItems();
101
+ $optionsCount = $attribute->getCount();
102
+ $this->_filterItems = array();
103
+ if(is_array($options)){
104
+ foreach ($options as $option) {
105
+
106
+ if($option['selected'] == true){
107
+ $this->_selectedFilterItems[$attribute->getAttributeCode()][] = $option;
108
+ continue;
109
+ }
110
+ $this->_filterItems[] = $option;
111
+ }
112
+ }
113
+ }
114
+
115
+ return $this->_filterItems;
116
+ }
117
+
118
+ }
app/code/community/Flagbit/FactFinder/Model/Layer/Filter/Attribute/Catalog.php ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Model class
12
+ *
13
+ * This helper class provides the Price export
14
+ *
15
+ * @category Mage
16
+ * @package Flagbit_FactFinder
17
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
18
+ * @author Joerg Weller <weller@flagbit.de>
19
+ * @version $Id$
20
+ */
21
+ class Flagbit_FactFinder_Model_Layer_Filter_Attribute_Catalog extends Flagbit_FactFinder_Model_Layer_Filter_Attribute_Abstract {
22
+
23
+
24
+
25
+ }
app/code/community/Flagbit/FactFinder/Model/Layer/Filter/Attribute/Catalogsearch.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Model class
12
+ *
13
+ * This helper class provides the Price export
14
+ *
15
+ * @category Mage
16
+ * @package Flagbit_FactFinder
17
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
18
+ * @author Joerg Weller <weller@flagbit.de>
19
+ * @version $Id$
20
+ */
21
+ class Flagbit_FactFinder_Model_Layer_Filter_Attribute_Catalogsearch extends Flagbit_FactFinder_Model_Layer_Filter_Attribute_Abstract {
22
+
23
+
24
+ /**
25
+ * Check whether specified attribute can be used in LN
26
+ *
27
+ * @param Mage_Catalog_Model_Resource_Eav_Attribute $attribute
28
+ * @return bool
29
+ */
30
+ protected function _getIsFilterableAttribute($attribute)
31
+ {
32
+ return $attribute->getIsFilterableInSearch();
33
+ }
34
+
35
+ }
app/code/community/Flagbit/FactFinder/Model/Layer/Filter/Item.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Flagbit_FactFinder_Model_Layer_Filter_Item extends Mage_Catalog_Model_Layer_Filter_Item {
3
+
4
+
5
+ /**
6
+ * Get url for remove item from filter
7
+ *
8
+ * @return string
9
+ */
10
+ public function getRemoveUrl()
11
+ {
12
+ if ($this->getFilter()->getRequestVar() == 'Category' && $this->getValue() != '') {
13
+ $query = array($this->getFilter()->getRequestVar()=>$this->getValue());
14
+ $params['_current'] = true;
15
+ $params['_use_rewrite'] = true;
16
+ $params['_query'] = $query;
17
+ $params['_escape'] = true;
18
+ return Mage::getUrl('*/*/*', $params);
19
+ } else {
20
+ return parent::getRemoveUrl();
21
+ }
22
+ }
23
+ }
app/code/community/Flagbit/FactFinder/Model/Mysql4/Campaign/Pushedproducts/Collection.php ADDED
@@ -0,0 +1,148 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Model class
12
+ *
13
+ * Search Collection with FACT-Finder Search Results
14
+ *
15
+ * @category Mage
16
+ * @package Flagbit_FactFinder
17
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
18
+ * @author Joerg Weller <weller@flagbit.de>
19
+ * @version $Id: Collection.php 644 2011-03-17 13:26:59Z weller $
20
+ */
21
+ class Flagbit_FactFinder_Model_Mysql4_Campaign_Pushedproducts_Collection
22
+ extends Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection
23
+ {
24
+ /**
25
+ * Get collection size
26
+ *
27
+ * @return int
28
+ */
29
+ public function getSize()
30
+ {
31
+ return count($this->_getCampaign()->getPushedProducts());
32
+ }
33
+
34
+ /**
35
+ * get Factfinder Search Adapter
36
+ *
37
+ * @return Flagbit_FactFinder_Model_Adapter
38
+ */
39
+ protected function _getCampaign()
40
+ {
41
+ if(Mage::helper('factfinder/search')->getIsEnabled(false, 'campaign')){
42
+ return Mage::getSingleton('factfinder/adapter')->getCampaigns();
43
+ }
44
+
45
+ return null;
46
+ }
47
+
48
+ /**
49
+ * Load entities records into items
50
+ *
51
+ * @return Mage_Eav_Model_Entity_Collection_Abstract
52
+ */
53
+ public function _loadEntities($printQuery = false, $logQuery = false)
54
+ {
55
+
56
+ $productIds = array();
57
+ $campaigns = $this->_getCampaign();
58
+
59
+ if (!$campaigns) {
60
+ return $this;
61
+ }
62
+
63
+ foreach($campaigns->getPushedProducts() as $record){
64
+ $productIds[$record->getId()] = new Varien_Object(
65
+ array(
66
+ 'similarity' => $record->getSimilarity(),
67
+ 'position' => $record->getPosition(),
68
+ 'original_position' => $record->getOriginalPosition()
69
+ )
70
+ );
71
+ }
72
+ $idFieldName = Mage::helper('factfinder/search')->getIdFieldName();
73
+
74
+ if (!empty($productIds)) {
75
+
76
+ // add Filter to Query
77
+ $this->addFieldToFilter(
78
+ $idFieldName,
79
+ array('in'=>array_keys($productIds))
80
+ );
81
+
82
+ $this->_pageSize = null;
83
+ $entity = $this->getEntity();
84
+
85
+ $this->getSelect()->reset(Zend_Db_Select::LIMIT_COUNT);
86
+ $this->getSelect()->reset(Zend_Db_Select::LIMIT_OFFSET);
87
+
88
+ $this->printLogQuery($printQuery, $logQuery);
89
+ Mage::helper('factfinder/debug')->log('Search SQL Query: '.$this->getSelect()->__toString());
90
+
91
+ try {
92
+ $rows = $this->_fetchAll($this->getSelect());
93
+ } catch (Exception $e) {
94
+ Mage::printException($e, $this->getSelect());
95
+ $this->printLogQuery(true, true, $this->getSelect());
96
+ throw $e;
97
+ }
98
+
99
+ $items = array();
100
+ foreach ($rows as $v) {
101
+ $items[$v[$idFieldName]] = $v;
102
+ }
103
+
104
+ foreach ($productIds as $productId => $additionalData){
105
+
106
+ if(empty($items[$productId])){
107
+ continue;
108
+ }
109
+ $v = array_merge($items[$productId], $additionalData->toArray());
110
+ $object = $this->getNewEmptyItem()
111
+ ->setData($v);
112
+
113
+ $this->addItem($object);
114
+ if (isset($this->_itemsById[$object->getId()])) {
115
+ $this->_itemsById[$object->getId()][] = $object;
116
+ }
117
+ else {
118
+ $this->_itemsById[$object->getId()] = array($object);
119
+ }
120
+ }
121
+
122
+ }
123
+ return $this;
124
+ }
125
+
126
+ /**
127
+ * Add search query filter
128
+ *
129
+ * @param Mage_CatalogSearch_Model_Query $query
130
+ * @return Mage_CatalogSearch_Model_Mysql4_Search_Collection
131
+ */
132
+ public function addSearchFilter($query)
133
+ {
134
+ return $this;
135
+ }
136
+
137
+ /**
138
+ * Set Order field
139
+ *
140
+ * @param string $attribute
141
+ * @param string $dir
142
+ * @return Mage_CatalogSearch_Model_Mysql4_Fulltext_Collection
143
+ */
144
+ public function setOrder($attribute, $dir='desc')
145
+ {
146
+ return $this;
147
+ }
148
+ }
app/code/community/Flagbit/FactFinder/Model/Mysql4/Product/Attribute/Collection.php ADDED
@@ -0,0 +1,144 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Model class
12
+ *
13
+ * Filter Attribute Collection
14
+ *
15
+ * @category Mage
16
+ * @package Flagbit_FactFinder
17
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
18
+ * @author Joerg Weller <weller@flagbit.de>
19
+ * @version $Id$
20
+ */
21
+ class Flagbit_FactFinder_Model_Mysql4_Product_Attribute_Collection extends Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Attribute_Collection {
22
+
23
+ protected $_result = null;
24
+ protected $_attributeLabels = null;
25
+ protected $_storeId = null;
26
+
27
+ /**
28
+ * Get collection size
29
+ *
30
+ * @return int
31
+ */
32
+ public function getSize()
33
+ {
34
+ return count($this->_getAdapter()->getAfterSearchNavigation());
35
+ }
36
+
37
+ /**
38
+ * get Adapter
39
+ *
40
+ * @return Flagbit_FactFinder_Model_Adapter
41
+ */
42
+ protected function _getAdapter()
43
+ {
44
+ return Mage::getSingleton('factfinder/adapter');
45
+ }
46
+
47
+ /**
48
+ * Load entities records into items
49
+ *
50
+ * @return Mage_Eav_Model_Entity_Collection_Abstract
51
+ */
52
+ public function load($printQuery = false, $logQuery = false)
53
+ {
54
+ if ($this->isLoaded()) {
55
+ return $this;
56
+ }
57
+
58
+ $result = $this->_getAdapter()->getAfterSearchNavigation();
59
+
60
+ if (count($result)) {
61
+ $this->resetData();
62
+
63
+ foreach ($result as $row) {
64
+ $item = $this->getNewEmptyItem();
65
+ if ($this->getIdFieldName()) {
66
+ $item->setIdFieldName($this->getIdFieldName());
67
+ }
68
+ $row['store_label'] = $this->_getStoreLabelsByAttributeCode($row['name']);
69
+ $item->addData($row);
70
+ $this->addItem($item);
71
+ }
72
+
73
+ $this->_setIsLoaded();
74
+ $this->_afterLoad();
75
+ }
76
+ return $this;
77
+ }
78
+
79
+
80
+ /**
81
+ * Add search query filter
82
+ *
83
+ * @param Mage_CatalogSearch_Model_Query $query
84
+ * @return Mage_CatalogSearch_Model_Mysql4_Search_Collection
85
+ */
86
+ public function addSearchFilter($query)
87
+ {
88
+ return $this;
89
+ }
90
+
91
+ /**
92
+ * Retrieve store labels by given attribute code
93
+ *
94
+ * @param string $attributeCode
95
+ * @return array
96
+ */
97
+ protected function _getStoreLabelsByAttributeCode($attributeCode)
98
+ {
99
+ if($this->_attributeLabels === null){
100
+ $entityType = Mage::getSingleton('eav/config')->getEntityType('catalog_product');
101
+
102
+ $values = array();
103
+
104
+ $select = $this->getConnection()->select()
105
+ ->from(array('main_table' => $this->getTable('eav/attribute')), array('attribute_code'))
106
+ ->joinLeft(
107
+ array('additional_table' => $this->getTable('eav/attribute_label')),
108
+ 'additional_table.attribute_id = main_table.attribute_id',
109
+ null
110
+ )
111
+ ->columns(array('value' => new Zend_Db_Expr('IF(additional_table.value IS NULL, main_table.frontend_label, additional_table.value)')))
112
+ ->where('main_table.entity_type_id = ?', $entityType->getEntityTypeId())
113
+ ->where('additional_table.store_id IS NULL OR additional_table.store_id=?', $this->_storeId);
114
+
115
+ $this->_attributeLabels = $this->getConnection()->fetchPairs($select);
116
+ }
117
+ return isset($this->_attributeLabels[$attributeCode]) ? $this->_attributeLabels[$attributeCode] : $attributeCode;
118
+ }
119
+
120
+ /**
121
+ * set Store ID
122
+ *
123
+ * @param int $storeId
124
+ * @return Flagbit_FactFinder_Model_Mysql4_Product_Attribute_Collection
125
+ */
126
+ public function setStoreId($storeId)
127
+ {
128
+ $this->_storeId = $storeId;
129
+ return $this;
130
+ }
131
+
132
+ /**
133
+ * Set Order field
134
+ *
135
+ * @param string $attribute
136
+ * @param string $dir
137
+ * @return Mage_CatalogSearch_Model_Mysql4_Fulltext_Collection
138
+ */
139
+ public function setOrder($attribute, $dir='desc')
140
+ {
141
+ return $this;
142
+ }
143
+
144
+ }
app/code/community/Flagbit/FactFinder/Model/Mysql4/Product/Recommendation/Collection.php ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Recommendation based product collection.
12
+ *
13
+ * Data is caught by FACT-Finder, passed to normal collection, works quite as if it was the default behavior.
14
+ *
15
+ * @category Mage
16
+ * @package Flagbit_FactFinder
17
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
18
+ * @author Michael Türk <türk@flagbit.de>
19
+ * @version $Id: Search.php 678 2011-08-01 13:02:50Z rudolf_batt $
20
+ */
21
+ class Flagbit_FactFinder_Model_Mysql4_Product_Recommendation_Collection extends Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection
22
+ {
23
+ /**
24
+ * Pass the product ids from FACT-Finder to the collection.
25
+ *
26
+ * @param array $recommendations Array with id information in Objects.
27
+ */
28
+ public function setRecommendations($recommendations)
29
+ {
30
+ $ids = array();
31
+ foreach ($recommendations as $recommendationItem) {
32
+ $ids[] = $recommendationItem->getId();
33
+ }
34
+
35
+ $searchHelper = Mage::helper('factfinder/search');
36
+ $idFieldName = $searchHelper->getIdFieldName();
37
+
38
+ $this->addAttributeToFilter($idFieldName, array('in' => $ids));
39
+
40
+ $order = new Zend_Db_Expr($this->getConnection()->quoteInto('find_in_set(`e`.`' . $idFieldName . '`, ?)', implode(',', $ids)));
41
+ $this->getSelect()->order($order);
42
+
43
+ return $this;
44
+ }
45
+
46
+
47
+ /**
48
+ * Helper function to exclude certain products that are already in the cart.
49
+ *
50
+ * @param array $ninIds Simple array of product ids
51
+ */
52
+ public function addExcludeProductFilter($ninIds)
53
+ {
54
+ $this->addAttributeToFilter($this->getIdFieldName(), array('nin' => $ninIds));
55
+
56
+ return $this;
57
+ }
58
+
59
+ }
app/code/community/Flagbit/FactFinder/Model/Mysql4/Scic/Queue.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Ressource Model class
12
+ *
13
+ * Queue for SCIC orders. Orders are sent to FACT-Finder asynchronously by cronjobs.
14
+ *
15
+ * @category Mage
16
+ * @package Flagbit_FactFinder
17
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
18
+ * @author Michael Türk <tuerk@flagbit.de>
19
+ * @version $Id: Processor.php 647 2011-03-21 10:32:14Z rudolf_batt $
20
+ */
21
+ class Flagbit_FactFinder_Model_Mysql4_Scic_Queue extends Mage_Core_Model_Mysql4_Abstract
22
+ {
23
+
24
+ /**
25
+ * Constructor with simple Magento initialisation
26
+ */
27
+ protected function _construct() {
28
+ $this->_init('factfinder/scic_queue', 'id');
29
+ }
30
+
31
+ }
app/code/community/Flagbit/FactFinder/Model/Mysql4/Scic/Queue/Collection.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Collection class
12
+ *
13
+ * Queue for SCIC orders. Orders are sent to FACT-Finder asynchronously by cronjobs.
14
+ *
15
+ * @category Mage
16
+ * @package Flagbit_FactFinder
17
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
18
+ * @author Michael Türk <tuerk@flagbit.de>
19
+ * @version $Id: Processor.php 647 2011-03-21 10:32:14Z rudolf_batt $
20
+ */
21
+ class Flagbit_FactFinder_Model_Mysql4_Scic_Queue_Collection extends Mage_Core_Model_Mysql4_Collection_Abstract
22
+ {
23
+ protected function _construct()
24
+ {
25
+ $this->_init('factfinder/scic_queue')
26
+ ->setOrder('store_id', 'ASC');
27
+ }
28
+ }
app/code/community/Flagbit/FactFinder/Model/Mysql4/Search/Collection.php ADDED
@@ -0,0 +1,130 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Model class
12
+ *
13
+ * Search Collection with FACT-Finder Search Results
14
+ *
15
+ * @category Mage
16
+ * @package Flagbit_FactFinder
17
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
18
+ * @author Joerg Weller <weller@flagbit.de>
19
+ * @version $Id$
20
+ */
21
+ class Flagbit_FactFinder_Model_Mysql4_Search_Collection
22
+ extends Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection
23
+ {
24
+ /**
25
+ * Get collection size
26
+ *
27
+ * @return int
28
+ */
29
+ public function getSize()
30
+ {
31
+ return $this->_getAdapter()->getSearchResultCount();
32
+ }
33
+
34
+ /**
35
+ * get Factfinder Search Adapter
36
+ *
37
+ * @return Flagbit_FactFinder_Model_Adapter
38
+ */
39
+ protected function _getAdapter()
40
+ {
41
+ return Mage::getSingleton('factfinder/adapter');
42
+ }
43
+
44
+ /**
45
+ * Load entities records into items
46
+ *
47
+ * @return Mage_Eav_Model_Entity_Collection_Abstract
48
+ */
49
+ public function _loadEntities($printQuery = false, $logQuery = false)
50
+ {
51
+
52
+ // get product Ids from Fact-Finder
53
+ $productIds = $this->_getAdapter()->getSearchResultProductIds();
54
+ $idFieldName = Mage::helper('factfinder/search')->getIdFieldName();
55
+
56
+ if (!empty($productIds)) {
57
+
58
+ // add Filter to Query
59
+ $this->addFieldToFilter(
60
+ $idFieldName,
61
+ array('in'=>array_keys($productIds))
62
+ );
63
+
64
+ $this->_pageSize = null;
65
+ $entity = $this->getEntity();
66
+
67
+ $this->getSelect()->reset(Zend_Db_Select::LIMIT_COUNT);
68
+ $this->getSelect()->reset(Zend_Db_Select::LIMIT_OFFSET);
69
+
70
+ $this->printLogQuery($printQuery, $logQuery);
71
+ Mage::helper('factfinder/debug')->log('Search SQL Query: '.$this->getSelect()->__toString());
72
+
73
+ try {
74
+ $rows = $this->_fetchAll($this->getSelect());
75
+ } catch (Exception $e) {
76
+ Mage::printException($e, $this->getSelect());
77
+ $this->printLogQuery(true, true, $this->getSelect());
78
+ throw $e;
79
+ }
80
+
81
+ $items = array();
82
+ foreach ($rows as $v) {
83
+ $items[trim($v[$idFieldName])] = $v;
84
+ }
85
+
86
+ foreach ($productIds as $productId => $additionalData){
87
+
88
+ if(empty($items[$productId])){
89
+ continue;
90
+ }
91
+ $v = array_merge($items[$productId], $additionalData->toArray());
92
+ $object = $this->getNewEmptyItem()
93
+ ->setData($v);
94
+
95
+ $this->addItem($object);
96
+ if (isset($this->_itemsById[$object->getId()])) {
97
+ $this->_itemsById[$object->getId()][] = $object;
98
+ }
99
+ else {
100
+ $this->_itemsById[$object->getId()] = array($object);
101
+ }
102
+ }
103
+
104
+ }
105
+ return $this;
106
+ }
107
+
108
+ /**
109
+ * Add search query filter
110
+ *
111
+ * @param Mage_CatalogSearch_Model_Query $query
112
+ * @return Mage_CatalogSearch_Model_Mysql4_Search_Collection
113
+ */
114
+ public function addSearchFilter($query)
115
+ {
116
+ return $this;
117
+ }
118
+
119
+ /**
120
+ * Set Order field
121
+ *
122
+ * @param string $attribute
123
+ * @param string $dir
124
+ * @return Mage_CatalogSearch_Model_Mysql4_Fulltext_Collection
125
+ */
126
+ public function setOrder($attribute, $dir='desc')
127
+ {
128
+ return $this;
129
+ }
130
+ }
app/code/community/Flagbit/FactFinder/Model/Mysql4/Search/Engine.php ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Model class
12
+ *
13
+ * FACT-Finder Search Engine Model
14
+ *
15
+ * @category Mage
16
+ * @package Flagbit_FactFinder
17
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
18
+ * @author Joerg Weller <weller@flagbit.de>
19
+ * @version $Id$
20
+ */
21
+ class Flagbit_FactFinder_Model_Mysql4_Search_Engine extends Mage_CatalogSearch_Model_Mysql4_Fulltext_Engine
22
+ {
23
+
24
+ /**
25
+ * Retrieve fulltext search result data collection
26
+ *
27
+ * @return Mage_CatalogSearch_Model_Mysql4_Fulltext_Collection
28
+ */
29
+ public function getResultCollection()
30
+ {
31
+ return Mage::getResourceModel('factfinder/search_collection');
32
+ }
33
+
34
+ /**
35
+ * Define if Layered Navigation is allowed
36
+ *
37
+ * @return bool
38
+ */
39
+ public function isLeyeredNavigationAllowed()
40
+ {
41
+ return true;
42
+ }
43
+
44
+ /**
45
+ * Define if engine is avaliable
46
+ *
47
+ * @return bool
48
+ */
49
+ public function test()
50
+ {
51
+ return Mage::helper('factfinder/search')->getIsEnabled(false, 'asn');
52
+ }
53
+ }
app/code/community/Flagbit/FactFinder/Model/Observer.php ADDED
@@ -0,0 +1,281 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Model class
12
+ *
13
+ * Observer for Magento events.
14
+ *
15
+ * @category Mage
16
+ * @package Flagbit_FactFinder
17
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
18
+ * @author Michael Türk <tuerk@flagbit.de>
19
+ * @version $Id: Processor.php 647 2011-03-21 10:32:14Z rudolf_batt $
20
+ */
21
+ class Flagbit_FactFinder_Model_Observer
22
+ {
23
+
24
+ /**
25
+ * Observer method.
26
+ * Sends information to FACT-Finder if item was added to cart.
27
+ *
28
+ * @param Varien_Event_Observer $observer
29
+ */
30
+ public function addToCartSendSCIC($observer)
31
+ {
32
+ if (!Mage::getStoreConfigFlag('factfinder/export/track_carts')) {
33
+ return;
34
+ }
35
+
36
+ $quoteItem = $observer->getQuoteItem();
37
+ $product = $observer->getProduct();
38
+
39
+ $searchHelper = Mage::helper('factfinder/search');
40
+ $idFieldName = $searchHelper->getIdFieldName();
41
+
42
+ $qty = $quoteItem->getQty();
43
+
44
+ $customerId = Mage::getSingleton('customer/session')->getCustomer()->getId();
45
+ if ($customerId) {
46
+ $customerId = md5('customer_' . $customerId);
47
+ }
48
+
49
+ try {
50
+ $scic = Mage::getModel('factfinder/adapter')->getScicAdapter();
51
+ $result = $scic->trackCart($product->getData($idFieldName), md5(Mage::getSingleton('core/session')->getSessionId()), $qty, $product->getFinalPrice($qty), $customerId);
52
+ }
53
+ catch (Exception $e) {
54
+ Mage::helper('factfinder/debug')->log($e->getMessage());
55
+ }
56
+ }
57
+
58
+
59
+ /**
60
+ * Observer method
61
+ * Adds all ordered items to queue that is sent to FACT-Finder by Cronjob.
62
+ *
63
+ * @param Varien_Event_Observer $observer
64
+ */
65
+ public function addOrderDetailsToSCICQueue($observer)
66
+ {
67
+ if (!Mage::getStoreConfigFlag('factfinder/export/track_checkout')) {
68
+ return;
69
+ }
70
+
71
+ $order = $observer->getOrder();
72
+ $customerId = $order->getCustomerId();
73
+ if ($customerId) {
74
+ $customerId = md5('customer_' . $customerId);
75
+ }
76
+
77
+ $searchHelper = Mage::helper('factfinder/search');
78
+ $idFieldName = $searchHelper->getIdFieldName();
79
+ if ($idFieldName == 'entity_id') {
80
+ $idFieldName = 'product_id'; // sales_order_item does not contain a entity_id
81
+ }
82
+
83
+ foreach ($order->getAllItems() as $item) {
84
+ if ($item->getParentItem() != null) {
85
+ continue;
86
+ }
87
+
88
+ try {
89
+ Mage::getModel('factfinder/scic_queue')
90
+ ->setProductId($item->getData($idFieldName))
91
+ ->setSid(md5(Mage::getSingleton('core/session')->getSessionId()))
92
+ ->setUserid($customerId)
93
+ ->setPrice($item->getPrice())
94
+ ->setCount($item->getQtyOrdered())
95
+ ->setStoreId(Mage::app()->getStore()->getId())
96
+ ->save();
97
+ }
98
+ catch (Exception $e) {
99
+ Mage::logException($e);
100
+ }
101
+ }
102
+ }
103
+
104
+
105
+ /**
106
+ * Cronjob observer method.
107
+ * Processes all orders given in SCIC queue and sends them to FACT-Finder.
108
+ *
109
+ */
110
+ public function processScicOrderQueue()
111
+ {
112
+ $queue = Mage::getModel('factfinder/scic_queue');
113
+ $collection = $queue->getCollection()->addOrder('store_id', 'ASC');
114
+
115
+ $storeId = null;
116
+ $scic = null;
117
+ foreach ($collection as $item) {
118
+ try {
119
+ if ($item->getStoreId() != $storeId) {
120
+ $scic = Mage::getModel('factfinder/adapter')->setStoreId($item->getStoreId())->getScicAdapter();
121
+ $storeId = $item->getStoreId();
122
+ }
123
+
124
+ $scic->trackCheckout($item->getProductId(), $item->getSid(), $item->getCount(), $item->getPrice(), $item->getUserid());
125
+ $item->delete($item);
126
+ }
127
+ catch (Exception $e) {
128
+ Mage::logException($e);
129
+ }
130
+ }
131
+ }
132
+
133
+
134
+ /**
135
+ * Checks configuration data before saving it to database.
136
+ *
137
+ * @param Varien_Event_Observer $observer
138
+ */
139
+ public function setEnabledFlagInFactFinderConfig($observer)
140
+ {
141
+ $request = $observer->getControllerAction()->getRequest();
142
+ if ($request->getParam('section') != 'factfinder') {
143
+ return;
144
+ }
145
+
146
+ $groups = $request->getPost('groups');
147
+ $website = $request->getParam('website');
148
+ $store = $request->getParam('store');
149
+
150
+ if (
151
+ is_array($groups['search'])
152
+ && is_array($groups['search']['fields'])
153
+ && is_array($groups['search']['fields']['enabled'])
154
+ && isset($groups['search']['fields']['enabled']['value'])
155
+ ) {
156
+ $value = $groups['search']['fields']['enabled']['value'];
157
+ }
158
+ elseif ($store) {
159
+ $value = Mage::app()->getWebsite($website)->getConfig('factfinder/search/enabled');
160
+ }
161
+ else {
162
+ $value = (string) Mage::getConfig()->getNode('default/factfinder/search/enabled');
163
+ }
164
+
165
+ if (!$value) {
166
+ return;
167
+ }
168
+
169
+ $errors = Mage::helper('factfinder/backend')->checkConfigData($groups['search']['fields']);
170
+ if (!empty($errors)) {
171
+ $groups['search']['fields']['enabled']['errors'] = $errors;
172
+ }
173
+
174
+ // if we have an error - unset inherit field so that Backend model processing is activated
175
+ if (!empty($errors) && isset($groups['search']['fields']['enabled']['inherit'])) {
176
+ unset($groups['search']['fields']['enabled']['inherit']);
177
+ $groups['search']['fields']['enabled']['value'] = $value;
178
+ }
179
+
180
+ $request->setPost('groups', $groups);
181
+ }
182
+
183
+
184
+ /**
185
+ * Replaces the link to the management cockpit functionality in the Magento Backend with the external link that
186
+ * opens in a new browser tab. Pretty dirty solution, but Magento does not offer any possibility to edit link urls
187
+ * in its backend menu model, nor does it allow to add absolute links for external sites.
188
+ *
189
+ * @param Varien_Event_Observer $observer
190
+ */
191
+ public function rewriteBackendMenuHtmlForCockpitRedirect($observer)
192
+ {
193
+ $block = $observer->getBlock();
194
+ if ($block->getNameInLayout() != 'menu') {
195
+ return;
196
+ }
197
+
198
+ $transport = $observer->getTransport();
199
+ $html = $transport->getHtml();
200
+
201
+ $matches = array();
202
+ $label = preg_quote(Mage::helper('factfinder')->__('FACT-Finder Business User Cockpit'));
203
+ $pattern = '/(\<a[^\>]*href=\"([^\"]*)\"[^\>]*)\>\w*\<span\>\w*' . $label . '\w*\<\/span\>/msU';
204
+ preg_match($pattern, $html, $matches);
205
+
206
+ $url = Mage::getSingleton('factfinder/adapter')->getAuthenticationUrl();
207
+ $replace = str_replace($matches[2], $url, $matches[1]) . ' target="_blank"';
208
+
209
+ $transport->setHtml(str_replace($matches[1], $replace, $html));
210
+ }
211
+
212
+ /**
213
+ * Adds layout handles based on FACT-Finder configuration.
214
+ *
215
+ * @param Varien_Event_Observer $observer
216
+ */
217
+ public function addActivationLayoutHandles($observer)
218
+ {
219
+ if (Mage::helper('factfinder/search')->getIsEnabled(false, 'suggest')) {
220
+ $layout = $observer->getLayout();
221
+ $update = $layout->getUpdate();
222
+ $update->addHandle('factfinder_suggest_enabled');
223
+ }
224
+ if (Mage::helper('factfinder/search')->getIsEnabled(false, 'advisory')) {
225
+ $layout = $observer->getLayout();
226
+ $update = $layout->getUpdate();
227
+ $update->addHandle('factfinder_advisory_enabled');
228
+ }
229
+ $request = Mage::app()->getRequest();
230
+ //catalogsearch_result_index
231
+ if (Mage::helper('factfinder/search')->getIsEnabled(false, 'clicktracking')
232
+ && $request->getModuleName() == 'catalogsearch'
233
+ && $request->getControllerName() == 'result'
234
+ && $request->getActionName() == 'index') {
235
+ $layout = $observer->getLayout();
236
+ $update = $layout->getUpdate();
237
+ $update->addHandle('factfinder_clicktracking_enabled');
238
+ }
239
+ }
240
+
241
+ /**
242
+ * Checks if the result set's size is one. If so the user is redirected to the product detail page. This is checked
243
+ * right before the first block is rendered so headers can still be sent. The ordinary collection load event is
244
+ * triggered too late.
245
+ *
246
+ * @param Varien_Event_Observer $observer
247
+ */
248
+ public function redirectToProductIfSingleResult($observer)
249
+ {
250
+ if (!Mage::helper('factfinder/search')->getIsEnabled() || !Mage::helper('factfinder/search')->getIsOnSearchPage() || Mage::registry('redirectAlreadyChecked')) {
251
+ return;
252
+ }
253
+
254
+ Mage::register('redirectAlreadyChecked', 1);
255
+
256
+ if (Mage::getStoreConfig('factfinder/config/redirectOnSingleResult')) {
257
+ $block = Mage::app()->getLayout()->getBlock('search_result_list');
258
+
259
+ if (!$block instanceof Mage_Catalog_Block_Product_List) {
260
+ return;
261
+ }
262
+
263
+ $collection = $block->getLoadedProductCollection();
264
+ $collection->load();
265
+
266
+ if (count($collection) == 1) {
267
+ $product = $collection->getFirstItem();
268
+ $response = Mage::app()->getResponse();
269
+ $response->setRedirect($product->getProductUrl(false));
270
+ $response->sendResponse();
271
+ exit;
272
+ }
273
+ }
274
+
275
+ $response = Mage::app()->getResponse();
276
+ $response->setHeader('Expires', gmdate("D, d M Y H:i:s", time() + 600), true);
277
+ $response->setHeader('Cache-Control', 'public, max-age=600, must-revalidate', true);
278
+ $response->setHeader('Pragma', null, true);
279
+ }
280
+
281
+ }
app/code/community/Flagbit/FactFinder/Model/Processor.php ADDED
@@ -0,0 +1,260 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Model class
12
+ *
13
+ * Request Processor for fast handling
14
+ *
15
+ * @category Mage
16
+ * @package Flagbit_FactFinder
17
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
18
+ * @author Joerg Weller <weller@flagbit.de>
19
+ * @version $Id$
20
+ */
21
+ class Flagbit_FactFinder_Model_Processor
22
+ {
23
+
24
+ const CACHE_TAG = 'FACTFINDER'; // Cache Tag
25
+ const REQUEST_ID_PREFIX = 'FACTFINDER_';
26
+ const XML_CONFIG_PATH = 'factfinder/search/';
27
+
28
+
29
+ /**
30
+ * Search Adapter
31
+ * @var Flagbit_FactFinder_Model_Adapter
32
+ */
33
+ protected $_searchAdapter;
34
+
35
+ /**
36
+ * Class constructor
37
+ */
38
+ public function __construct()
39
+ {
40
+ $uri = $this->_getFullPageUrl();
41
+
42
+ $this->_requestId = $uri;
43
+ $this->_requestCacheId = $this->prepareCacheId($this->_requestId);
44
+ $this->_requestTags = array(self::CACHE_TAG);
45
+ }
46
+
47
+ /**
48
+ * get Fact-Finder Search Adapter
49
+ *
50
+ * @return Flagbit_FactFinder_Model_Adapter
51
+ */
52
+ public function getSearchAdapter()
53
+ {
54
+ if($this->_searchAdapter === null){
55
+ $logger = new Flagbit_FactFinder_Helper_Debug();
56
+ $this->_searchAdapter = new Flagbit_FactFinder_Model_Adapter($logger);
57
+ }
58
+ return $this->_searchAdapter;
59
+ }
60
+
61
+
62
+ /**
63
+ * Get page content from cache storage
64
+ *
65
+ * @param string $content
66
+ * @return string | false
67
+ */
68
+ public function extractContent($content)
69
+ {
70
+ // handle in App Request if "factfinder" in Request path
71
+ if (!$content
72
+ && strpos($this->_requestId, 'factfinder')
73
+ && $this->isAllowed()) {
74
+
75
+ $requestCacheId = $this->prepareCacheId($this->getRequestId().'request');
76
+ $request = Mage::app()->loadCache($requestCacheId);
77
+ if ($request) {
78
+ $content = $this->handleWithoutAppRequest($request);
79
+ }
80
+
81
+ }
82
+ return $content;
83
+ }
84
+
85
+ /**
86
+ * handle in App Requests
87
+ *
88
+ * @param string $request
89
+ * @return string
90
+ */
91
+ public function handleInAppRequest($request)
92
+ {
93
+ $requestCacheId = $this->prepareCacheId($this->getRequestId().'request');
94
+ Mage::app()->saveCache($request, $requestCacheId, $this->getRequestTags());
95
+
96
+ $configCacheId = $this->prepareCacheId($this->getRequestId().'config');
97
+ Mage::app()->saveCache(serialize(Mage::getStoreConfig('factfinder/search')), $configCacheId, $this->getRequestTags());
98
+
99
+ return $this->_handleRequest($request);
100
+ }
101
+
102
+ /**
103
+ * hanlde without App Requests
104
+ *
105
+ * @param string $request
106
+ * @return string
107
+ */
108
+ public function handleWithoutAppRequest($request)
109
+ {
110
+ $configCacheId = $this->prepareCacheId($this->getRequestId().'config');
111
+ $config = null;
112
+ try{
113
+ $config = unserialize(Mage::app()->loadCache($configCacheId));
114
+ } catch (Exception $e){
115
+ return;
116
+ }
117
+ if(!is_array($config) || empty($config)){
118
+ return;
119
+ }
120
+ $this->getSearchAdapter()->setConfiguration($config);
121
+ return $this->_handleRequest($request);
122
+ }
123
+
124
+ /**
125
+ * handle Requests
126
+ *
127
+ * @param unknown_type $request
128
+ * @return string
129
+ */
130
+ protected function _handleRequest($request)
131
+ {
132
+ switch ($request){
133
+
134
+ case 'factfinder_proxy_scic':
135
+ $scic = $this->getSearchAdapter()->getScicAdapter();
136
+ return $scic->doTrackingFromRequest();
137
+ break;
138
+
139
+ case 'factfinder_proxy_suggest':
140
+ return $this->getSearchAdapter()->getSuggestResultJsonp($this->_getRequestParam('query'), $this->_getRequestParam('jquery_callback'));
141
+ break;
142
+
143
+ }
144
+ }
145
+
146
+ /**
147
+ * get Request Param by Key
148
+ *
149
+ * @param unknown_type $key
150
+ * @return string
151
+ */
152
+ protected function _getRequestParam($key)
153
+ {
154
+ $value = null;
155
+ if(isset($_REQUEST[$key])){
156
+ $value = $_REQUEST[$key];
157
+ }
158
+ return $value;
159
+ }
160
+
161
+ /**
162
+ * Return current page base url
163
+ *
164
+ * @return string
165
+ */
166
+ protected function _getFullPageUrl()
167
+ {
168
+ $uri = false;
169
+ /**
170
+ * Define server HTTP HOST
171
+ */
172
+ if (isset($_SERVER['HTTP_HOST'])) {
173
+ $uri = $_SERVER['HTTP_HOST'];
174
+ } elseif (isset($_SERVER['SERVER_NAME'])) {
175
+ $uri = $_SERVER['SERVER_NAME'];
176
+ }
177
+
178
+ /**
179
+ * Define request URI
180
+ */
181
+ if ($uri) {
182
+ if (isset($_SERVER['REQUEST_URI'])) {
183
+ $uri.= $_SERVER['REQUEST_URI'];
184
+ } elseif (!empty($_SERVER['IIS_WasUrlRewritten']) && !empty($_SERVER['UNENCODED_URL'])) {
185
+ $uri.= $_SERVER['UNENCODED_URL'];
186
+ } elseif (isset($_SERVER['ORIG_PATH_INFO'])) {
187
+ $uri.= $_SERVER['ORIG_PATH_INFO'];
188
+ if (!empty($_SERVER['QUERY_STRING'])) {
189
+ $uri.= $_SERVER['QUERY_STRING'];
190
+ }
191
+ }
192
+ }
193
+
194
+ $pieces = explode('?', $uri);
195
+ $uri = array_shift($pieces);
196
+
197
+ return $uri;
198
+ }
199
+
200
+ /**
201
+ * Prepare page identifier
202
+ *
203
+ * @param string $id
204
+ * @return string
205
+ */
206
+ public function prepareCacheId($id)
207
+ {
208
+ return self::REQUEST_ID_PREFIX . md5($id);
209
+ }
210
+
211
+ /**
212
+ * Get HTTP request identifier
213
+ *
214
+ * @return string
215
+ */
216
+ public function getRequestId()
217
+ {
218
+ return $this->_requestId;
219
+ }
220
+
221
+ /**
222
+ * Get page identifier for loading page from cache
223
+ * @return string
224
+ */
225
+ public function getRequestCacheId()
226
+ {
227
+ return $this->_requestCacheId;
228
+ }
229
+
230
+ /**
231
+ * Check if processor is allowed for current HTTP request.
232
+ * Disable processing HTTPS requests and requests with "NO_CACHE" cookie
233
+ *
234
+ * @return bool
235
+ */
236
+ public function isAllowed()
237
+ {
238
+ if (!$this->_requestId) {
239
+ return false;
240
+ }
241
+ if (isset($_COOKIE['NO_CACHE'])) {
242
+ return false;
243
+ }
244
+ if (isset($_GET['no_cache'])) {
245
+ return false;
246
+ }
247
+
248
+ return true;
249
+ }
250
+
251
+ /**
252
+ * Get cache request associated tags
253
+ * @return array
254
+ */
255
+ public function getRequestTags()
256
+ {
257
+ return $this->_requestTags;
258
+ }
259
+
260
+ }
app/code/community/Flagbit/FactFinder/Model/Scic/Queue.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Model class
12
+ *
13
+ * Queue for SCIC orders. Orders are sent to FACT-Finder asynchronously by cronjobs.
14
+ *
15
+ * @category Mage
16
+ * @package Flagbit_FactFinder
17
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
18
+ * @author Michael Türk <tuerk@flagbit.de>
19
+ * @version $Id: Processor.php 647 2011-03-21 10:32:14Z rudolf_batt $
20
+ */
21
+ class Flagbit_FactFinder_Model_Scic_Queue extends Mage_Core_Model_Abstract
22
+ {
23
+ public function _construct()
24
+ {
25
+ $this->_init('factfinder/scic_queue');
26
+ }
27
+ }
app/code/community/Flagbit/FactFinder/Model/System/Config/Backend/Attributes.php ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_CatalogInventory
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ /**
28
+ * Backend for serialized array data
29
+ *
30
+ */
31
+ class Flagbit_FactFinder_Model_System_Config_Backend_Attributes extends Mage_Core_Model_Config_Data
32
+ {
33
+ /**
34
+ * Process data after load
35
+ */
36
+ protected function _afterLoad()
37
+ {
38
+ $value = $this->getValue();
39
+ $value = Mage::helper('factfinder/backend')->makeArrayFieldValue($value);
40
+ $this->setValue($value);
41
+ }
42
+
43
+ /**
44
+ * Prepare data before save
45
+ */
46
+ protected function _beforeSave()
47
+ {
48
+ $value = $this->getValue();
49
+ $value = Mage::helper('factfinder/backend')->makeStorableArrayFieldValue($value);
50
+ $this->setValue($value);
51
+ }
52
+ }
app/code/community/Flagbit/FactFinder/Model/System/Config/Backend/Enabled.php ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Model class
12
+ *
13
+ * Status Enabled Config Field Backend
14
+ *
15
+ * @category Mage
16
+ * @package Flagbit_FactFinder
17
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
18
+ * @author Joerg Weller <weller@flagbit.de>
19
+ * @version $Id$
20
+ */
21
+ class Flagbit_FactFinder_Model_System_Config_Backend_Enabled extends Mage_Core_Model_Config_Data {
22
+
23
+ /**
24
+ * Check request for errors found by Helper and Observer. It will print error messages if errors found and
25
+ * in that case set value to 0.
26
+ *
27
+ * @return Flagbit_FactFinder_Model_System_Config_Backend_Enabled
28
+ */
29
+ protected function _beforeSave()
30
+ {
31
+ if (!$this->getValue()) {
32
+ return $this;
33
+ }
34
+
35
+ $groups = Mage::app()->getRequest()->getPost('groups');
36
+ if (isset($groups['search']['fields']['enabled']['errors'])) {
37
+ $errors = $groups['search']['fields']['enabled']['errors'];
38
+ if (is_array($errors)) {
39
+ Mage::getSingleton('adminhtml/session')->addError(Mage::helper('factfinder')->__('FACT-Finder cannot be activated:').' <br/>'. implode('<br/>', $errors));
40
+ }
41
+ elseif (is_string($errors)) {
42
+ Mage::getSingleton('adminhtml/session')->addError(Mage::helper('factfinder')->__('FACT-Finder cannot be activated:').' <br/>' . $errors);
43
+ }
44
+ else {
45
+ Mage::getSingleton('adminhtml/session')->addError(Mage::helper('factfinder')->__('FACT-Finder cannot be activated:'));
46
+ }
47
+ $this->setValue('0');
48
+ }
49
+ else {
50
+ Mage::app()->cleanCache(array(Flagbit_FactFinder_Model_Processor::CACHE_TAG));
51
+ }
52
+
53
+ return $this;
54
+ }
55
+
56
+
57
+ }
app/code/community/Flagbit/FactFinder/Model/System/Config/Source/Authtype.php ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Model class
12
+ *
13
+ * provides Authtype Options
14
+ *
15
+ * @category Mage
16
+ * @package Flagbit_FactFinder
17
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
18
+ * @author Joerg Weller <weller@flagbit.de>
19
+ * @version $Id$
20
+ */
21
+ class Flagbit_FactFinder_Model_System_Config_Source_Authtype
22
+ {
23
+ /**
24
+ * get Authtypes as Option Array
25
+ *
26
+ * @return array
27
+ */
28
+ public function toOptionArray()
29
+ {
30
+ return array(
31
+ array(
32
+ 'value' => 'http',
33
+ 'label' => Mage::helper('factfinder')->__('http')
34
+ ),
35
+ array(
36
+ 'value' => 'simple',
37
+ 'label' => Mage::helper('factfinder')->__('simple')
38
+ ),
39
+ array(
40
+ 'value' => 'advanced',
41
+ 'label' => Mage::helper('factfinder')->__('advanced')
42
+ )
43
+ );
44
+ }
45
+ }
app/code/community/Flagbit/FactFinder/Model/System/Config/Source/Identifier.php ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Model class
12
+ *
13
+ * provides Identifier Options
14
+ *
15
+ * @category Mage
16
+ * @package Flagbit_FactFinder
17
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
18
+ * @author Joerg Weller <weller@flagbit.de>
19
+ * @version $Id$
20
+ */
21
+ class Flagbit_FactFinder_Model_System_Config_Source_Identifier
22
+ {
23
+ /**
24
+ * get Authtypes as Option Array
25
+ *
26
+ * @return array
27
+ */
28
+ public function toOptionArray()
29
+ {
30
+ return array(
31
+ array(
32
+ 'value' => 'entity_id',
33
+ 'label' => Mage::helper('factfinder')->__('Product ID (default)')
34
+ ),
35
+ array(
36
+ 'value' => 'sku',
37
+ 'label' => Mage::helper('factfinder')->__('Product SKU')
38
+ )
39
+ );
40
+ }
41
+ }
app/code/community/Flagbit/FactFinder/controllers/Adminhtml/Factfinder/CockpitController.php ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Black class
12
+ *
13
+ * This Block class provides the FACT-Finder Business User Cockpit Authentication URL
14
+ *
15
+ * @category Mage
16
+ * @package Flagbit_FactFinder
17
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
18
+ * @author Joerg Weller <weller@flagbit.de>
19
+ * @version $Id$
20
+ */
21
+ class Flagbit_FactFinder_Adminhtml_Factfinder_CockpitController extends Mage_Adminhtml_Controller_Action
22
+ {
23
+
24
+ /**
25
+ * Load layout, set active menu and breadcrumbs
26
+ *
27
+ * @return Mage_Widget_Adminhtml_Widget_InstanceController
28
+ */
29
+ protected function _initAction()
30
+ {
31
+ $this->loadLayout()
32
+ ->_setActiveMenu('catalog/factfinder_cockpit')
33
+ ->_addBreadcrumb(Mage::helper('factfinder')->__('Catalog'),
34
+ Mage::helper('factfinder')->__('Catalog'))
35
+ ->_addBreadcrumb(Mage::helper('factfinder')->__('FACT-Finder Business User Cockpit'),
36
+ Mage::helper('factfinder')->__('FACT-Finder Business User Cockpit'));
37
+ return $this;
38
+ }
39
+
40
+ /**
41
+ * FACT-Finder Business User Cockpit Action
42
+ */
43
+ public function indexAction()
44
+ {
45
+ $this->_title($this->__('factfinder'))->_title($this->__('FACT-Finder Business User Cockpit'));
46
+
47
+ $this->_initAction()
48
+ ->renderLayout();
49
+ }
50
+
51
+
52
+
53
+ }
app/code/community/Flagbit/FactFinder/controllers/ExportController.php ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Controller class
12
+ *
13
+ * This class the Export Controller
14
+ * It provides a Products, Prices and Stocks Export
15
+ *
16
+ * @category Mage
17
+ * @package Flagbit_FactFinder
18
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
19
+ * @author Joerg Weller <weller@flagbit.de>
20
+ * @version $Id$
21
+ */
22
+ class Flagbit_FactFinder_ExportController extends Mage_Core_Controller_Front_Action {
23
+
24
+ const XML_AUTH_PASSWORD_PATH = 'factfinder/search/auth_password';
25
+
26
+ /**
27
+ * handle Export Authentification
28
+ *
29
+ * @return Mage_Core_Controller_Varien_Action
30
+ */
31
+ public function preDispatch()
32
+ {
33
+ $this->_getStoreId();
34
+ $password = md5(Mage::getStoreConfig(self::XML_AUTH_PASSWORD_PATH));
35
+
36
+ if ($password == '' || $password != $this->getRequest()->getParam('key')) {
37
+ $this->setFlag('', self::FLAG_NO_DISPATCH, true);
38
+ }
39
+
40
+ return parent::preDispatch();
41
+ }
42
+
43
+ /**
44
+ * get current Store ID
45
+ *
46
+ * @return int
47
+ */
48
+ protected function _getStoreId()
49
+ {
50
+ if ($storeId = $this->getRequest()->getParam('store')) {
51
+ Mage::app()->setCurrentStore($storeId);
52
+ }
53
+
54
+ return Mage::app()->getStore()->getId();
55
+ }
56
+
57
+ /**
58
+ * Initialize Product Export
59
+ */
60
+ public function productAction()
61
+ {
62
+ $exportModel = Mage::getModel('factfinder/export_product');
63
+ $exportModel->doExport(
64
+ $this->_getStoreId()
65
+ );
66
+ }
67
+
68
+ /**
69
+ * Initialize Price Export
70
+ */
71
+ public function priceAction()
72
+ {
73
+ $exportModel = Mage::getModel('factfinder/export_price');
74
+ $exportModel->doExport(
75
+ $this->_getStoreId()
76
+ );
77
+ }
78
+
79
+ /**
80
+ * Initialize Stock Export
81
+ */
82
+ public function stockAction()
83
+ {
84
+ $exportModel = Mage::getModel('factfinder/export_stock');
85
+ $exportModel->doExport(
86
+ $this->_getStoreId()
87
+ );
88
+ }
89
+ }
app/code/community/Flagbit/FactFinder/controllers/ProxyController.php ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Controller class
12
+ *
13
+ * This class the Proxy Controller
14
+ * It provides a scic and a suggest Action
15
+ *
16
+ * @category Mage
17
+ * @package Flagbit_FactFinder
18
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
19
+ * @author Joerg Weller <weller@flagbit.de>
20
+ * @version $Id$
21
+ */
22
+ class Flagbit_FactFinder_ProxyController extends Mage_Core_Controller_Front_Action {
23
+
24
+ /**
25
+ * scic Action
26
+ */
27
+ public function scicAction()
28
+ {
29
+ $this->getResponse()->setBody(
30
+ Mage::getModel('factfinder/processor')->handleInAppRequest($this->getFullActionName())
31
+ );
32
+ }
33
+
34
+
35
+
36
+ /**
37
+ * suggest Action
38
+ */
39
+ public function suggestAction()
40
+ {
41
+ $this->getResponse()->setHeader("Content-Type:", "text/javascript;charset=utf-8", true);
42
+ $this->getResponse()->setBody(
43
+ Mage::getModel('factfinder/processor')->handleInAppRequest($this->getFullActionName())
44
+ );
45
+ }
46
+ }
app/code/community/Flagbit/FactFinder/documentation/Installation_FACT-Finder_Magento_de.pdf ADDED
Binary file
app/code/community/Flagbit/FactFinder/documentation/Installation_FACT-Finder_Magento_en.pdf ADDED
Binary file
app/code/community/Flagbit/FactFinder/etc/adminhtml.xml ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <!--
3
+ /**
4
+ * Flagbit_FactFinder
5
+ *
6
+ * @category Mage
7
+ * @package Flagbit_FactFinder
8
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
9
+ */
10
+
11
+ /**
12
+ * Module Config
13
+ *
14
+ * @category Mage
15
+ * @package Flagbit_FactFinder
16
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
17
+ * @author Joerg Weller <weller@flagbit.de>
18
+ * @version $Id$
19
+ */
20
+ -->
21
+ <config>
22
+ <acl>
23
+ <resources>
24
+ <admin>
25
+ <children>
26
+ <catalog>
27
+ <children>
28
+ <factfinder_cockpit translate="title" module="factfinder">
29
+ <title>FACT-Finder Business User Cockpit</title>
30
+ <sort_order>35</sort_order>
31
+ </factfinder_cockpit>
32
+ </children>
33
+ </catalog>
34
+ </children>
35
+ </admin>
36
+ </resources>
37
+ </acl>
38
+ <menu>
39
+ <catalog>
40
+ <children>
41
+ <factfinder_cockpit translate="title" module="factfinder">
42
+ <title>FACT-Finder Business User Cockpit</title>
43
+ <sort_order>35</sort_order>
44
+ <action>adminhtml/factfinder_cockpit</action>
45
+ </factfinder_cockpit>
46
+ </children>
47
+ </catalog>
48
+ </menu>
49
+ </config>
app/code/community/Flagbit/FactFinder/etc/config.xml ADDED
@@ -0,0 +1,292 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <!--
3
+ /**
4
+ * Flagbit_FactFinder
5
+ *
6
+ * @category Mage
7
+ * @package Flagbit_FactFinder
8
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
9
+ */
10
+
11
+ /**
12
+ * Module Config
13
+ *
14
+ * @category Mage
15
+ * @package Flagbit_FactFinder
16
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
17
+ * @author Joerg Weller <weller@flagbit.de>
18
+ * @version $Id$
19
+ */
20
+ -->
21
+ <config>
22
+ <modules>
23
+ <Flagbit_FactFinder>
24
+ <active>true</active>
25
+ <version>3.3.6</version>
26
+ </Flagbit_FactFinder>
27
+ </modules>
28
+ <global>
29
+ <helpers>
30
+ <factfinder>
31
+ <class>Flagbit_FactFinder_Helper</class>
32
+ </factfinder>
33
+ </helpers>
34
+ <blocks>
35
+ <factfinder>
36
+ <class>Flagbit_FactFinder_Block</class>
37
+ </factfinder>
38
+ <catalogsearch>
39
+ <rewrite>
40
+ <term>Flagbit_FactFinder_Block_TagCloud</term>
41
+ <layer>Flagbit_FactFinder_Block_Layer</layer>
42
+ </rewrite>
43
+ </catalogsearch>
44
+ <catalog>
45
+ <rewrite>
46
+ <layer_view>Flagbit_FactFinder_Block_Layer</layer_view>
47
+ <product_list_upsell>Flagbit_FactFinder_Block_Product_List_Upsell</product_list_upsell>
48
+ <product_list_crosssell>Flagbit_FactFinder_Block_Product_List_Crosssell</product_list_crosssell>
49
+ </rewrite>
50
+ </catalog>
51
+ <checkout>
52
+ <rewrite>
53
+ <cart_crosssell>Flagbit_FactFinder_Block_Cart_Crosssell</cart_crosssell>
54
+ </rewrite>
55
+ </checkout>
56
+ <enterprise_search>
57
+ <rewrite>
58
+ <catalogsearch_layer>Flagbit_FactFinder_Block_Layer</catalogsearch_layer>
59
+ <catalog_layer_view>Flagbit_FactFinder_Block_Layer</catalog_layer_view>
60
+ </rewrite>
61
+ </enterprise_search>
62
+ <xmlconnect>
63
+ <rewrite>
64
+ <catalog_search>Flagbit_FactFinder_Block_XmlConnect_Catalog_Search</catalog_search>
65
+ <catalog_search_suggest>Flagbit_FactFinder_Block_XmlConnect_Catalog_Search_Suggest</catalog_search_suggest>
66
+ <catalog_product_list>Flagbit_FactFinder_Block_XmlConnect_Catalog_Product_List</catalog_product_list>
67
+ </rewrite>
68
+ </xmlconnect>
69
+ </blocks>
70
+ <models>
71
+ <factfinder>
72
+ <class>Flagbit_FactFinder_Model</class>
73
+ <resourceModel>factfinder_mysql4</resourceModel>
74
+ </factfinder>
75
+ <factfinder_mysql4>
76
+ <class>Flagbit_FactFinder_Model_Mysql4</class>
77
+ <entities>
78
+ <scic_queue><table>flagbit_factfinder_scic_queue</table></scic_queue>
79
+ </entities>
80
+ </factfinder_mysql4>
81
+ <catalogsearch>
82
+ <rewrite>
83
+ <layer>Flagbit_FactFinder_Model_Layer</layer>
84
+ <layer_filter_attribute>Flagbit_FactFinder_Model_Layer_Filter_Attribute_Catalogsearch</layer_filter_attribute>
85
+ </rewrite>
86
+ </catalogsearch>
87
+ <catalog>
88
+ <rewrite>
89
+ <layer>Flagbit_FactFinder_Model_Layer</layer>
90
+ <layer_filter_attribute>Flagbit_FactFinder_Model_Layer_Filter_Attribute_Catalog</layer_filter_attribute>
91
+ </rewrite>
92
+ </catalog>
93
+ </models>
94
+ <resources>
95
+ <factfinder_setup>
96
+ <setup>
97
+ <module>Flagbit_FactFinder</module>
98
+ </setup>
99
+ <connection>
100
+ <use>core_setup</use>
101
+ </connection>
102
+ </factfinder_setup>
103
+ </resources>
104
+ <events>
105
+ <controller_action_predispatch_adminhtml_system_config_save>
106
+ <observers>
107
+ <setEnabledFlagInFactFinderConfig>
108
+ <class>factfinder/observer</class>
109
+ <method>setEnabledFlagInFactFinderConfig</method>
110
+ </setEnabledFlagInFactFinderConfig>
111
+ </observers>
112
+ </controller_action_predispatch_adminhtml_system_config_save>
113
+ </events>
114
+ </global>
115
+ <frontend>
116
+ <layout>
117
+ <updates>
118
+ <factfinder>
119
+ <file>factfinder.xml</file>
120
+ </factfinder>
121
+ </updates>
122
+ </layout>
123
+ <routers>
124
+ <factfinder>
125
+ <use>standard</use>
126
+ <args>
127
+ <module>Flagbit_FactFinder</module>
128
+ <frontName>factfinder</frontName>
129
+ </args>
130
+ </factfinder>
131
+ </routers>
132
+ <events>
133
+ <checkout_cart_product_add_after>
134
+ <observers>
135
+ <addToCartSendSCIC>
136
+ <class>factfinder/observer</class>
137
+ <method>addToCartSendSCIC</method>
138
+ </addToCartSendSCIC>
139
+ </observers>
140
+ </checkout_cart_product_add_after>
141
+ <sales_order_place_after>
142
+ <observers>
143
+ <addOrderDetailsToSCICQueue>
144
+ <class>factfinder/observer</class>
145
+ <method>addOrderDetailsToSCICQueue</method>
146
+ </addOrderDetailsToSCICQueue>
147
+ </observers>
148
+ </sales_order_place_after>
149
+ <controller_action_layout_load_before>
150
+ <observers>
151
+ <addActivationLayoutHandles>
152
+ <class>factfinder/observer</class>
153
+ <method>addActivationLayoutHandles</method>
154
+ </addActivationLayoutHandles>
155
+ </observers>
156
+ </controller_action_layout_load_before>
157
+ <core_block_abstract_to_html_before>
158
+ <observers>
159
+ <redirectToProductIfSingleResult>
160
+ <class>factfinder/observer</class>
161
+ <method>redirectToProductIfSingleResult</method>
162
+ </redirectToProductIfSingleResult>
163
+ </observers>
164
+ </core_block_abstract_to_html_before>
165
+ </events>
166
+ <translate>
167
+ <modules>
168
+ <Flagbit_FactFinder>
169
+ <files>
170
+ <default>Flagbit_FactFinder.csv</default>
171
+ </files>
172
+ </Flagbit_FactFinder>
173
+ </modules>
174
+ </translate>
175
+ </frontend>
176
+ <adminhtml>
177
+ <acl>
178
+ <resources>
179
+ <admin>
180
+ <children>
181
+ <system>
182
+ <children>
183
+ <config>
184
+ <children>
185
+ <factfinder>
186
+ <title>FACT-Finder</title>
187
+ </factfinder>
188
+ </children>
189
+ </config>
190
+ </children>
191
+ </system>
192
+ </children>
193
+ </admin>
194
+ </resources>
195
+ </acl>
196
+ <translate>
197
+ <modules>
198
+ <Flagbit_FactFinder>
199
+ <files>
200
+ <default>Flagbit_FactFinder.csv</default>
201
+ </files>
202
+ </Flagbit_FactFinder>
203
+ </modules>
204
+ </translate>
205
+ <layout>
206
+ <updates>
207
+ <factfinder>
208
+ <file>factfinder.xml</file>
209
+ </factfinder>
210
+ </updates>
211
+ </layout>
212
+ <events>
213
+ <core_block_abstract_to_html_after>
214
+ <observers>
215
+ <rewriteBackendMenuHtmlForCockpitRedirect>
216
+ <class>factfinder/observer</class>
217
+ <method>rewriteBackendMenuHtmlForCockpitRedirect</method>
218
+ </rewriteBackendMenuHtmlForCockpitRedirect>
219
+ </observers>
220
+ </core_block_abstract_to_html_after>
221
+ </events>
222
+ </adminhtml>
223
+ <admin>
224
+ <routers>
225
+ <adminhtml>
226
+ <args>
227
+ <modules>
228
+ <factfinder before="Mage_Adminhtml">Flagbit_FactFinder_Adminhtml</factfinder>
229
+ </modules>
230
+ </args>
231
+ </adminhtml>
232
+ </routers>
233
+ </admin>
234
+ <crontab>
235
+ <jobs>
236
+ <factfinder_scic_queue_processing>
237
+ <schedule><cron_expr>* * * * *</cron_expr></schedule>
238
+ <run><model>factfinder/observer::processScicOrderQueue</model></run>
239
+ </factfinder_scic_queue_processing>
240
+ </jobs>
241
+ </crontab>
242
+ <default>
243
+ <catalog>
244
+ <search>
245
+ <engine>factfinder/search_engine</engine>
246
+ </search>
247
+ </catalog>
248
+ <factfinder>
249
+ <version>2.3.15</version>
250
+ <revision>$Rev: 25896 $</revision>
251
+ <debug>true</debug>
252
+
253
+ <!-- search settings: WARNING: dont change settings here, please use the Magento backoffice ...
254
+ if you still have to change something here, dont forget to clear the configuration cache -->
255
+ <search>
256
+ <address>magento.fact-finder.de</address>
257
+ <port>8080</port>
258
+ <protocol>http</protocol> <!-- possible values: http, https -->
259
+
260
+ <auth_user>client</auth_user>
261
+ <auth_password></auth_password>
262
+ <auth_type>advanced</auth_type> <!-- possible values: http (for FF <= 6.4); simple | advanced (for FF >= 6.5)-->
263
+ <auth_advancedPrefix>FACT-FINDER</auth_advancedPrefix>
264
+ <auth_advancedPostfix>FACT-FINDER</auth_advancedPostfix>
265
+
266
+ <context>MagentoSearch65</context>
267
+ <channel></channel>
268
+ <language></language>
269
+ </search>
270
+ <export>
271
+ <urls>0</urls>
272
+ <track_carts>1</track_carts>
273
+ <track_checkout>1</track_checkout>
274
+ </export>
275
+ <config>
276
+ <identifier>entity_id</identifier>
277
+ <proxy>0</proxy>
278
+ <debug>0</debug>
279
+ <navigation>0</navigation>
280
+ <upsell>0</upsell>
281
+ <crosssell>0</crosssell>
282
+ </config>
283
+
284
+ <!-- encoding settings -->
285
+ <encoding>
286
+ <pageContent>UTF-8</pageContent>
287
+ <serverURI>UTF-8</serverURI>
288
+ <pageURI>UTF-8</pageURI>
289
+ </encoding>
290
+ </factfinder>
291
+ </default>
292
+ </config>
app/code/community/Flagbit/FactFinder/etc/system.xml ADDED
@@ -0,0 +1,323 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <!--
3
+ /**
4
+ * Flagbit_FactFinder
5
+ *
6
+ * @category Mage
7
+ * @package Flagbit_FactFinder
8
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
9
+ */
10
+
11
+ /**
12
+ * System Config
13
+ *
14
+ * @category Mage
15
+ * @package Flagbit_FactFinder
16
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
17
+ * @author Joerg Weller <weller@flagbit.de>
18
+ * @version $Id$
19
+ */
20
+ -->
21
+ <config>
22
+ <sections>
23
+ <factfinder translate="label" module="factfinder">
24
+ <label>FACT-Finder</label>
25
+ <tab>catalog</tab>
26
+ <sort_order>420</sort_order>
27
+ <frontend_type>text</frontend_type>
28
+ <show_in_default>1</show_in_default>
29
+ <show_in_website>1</show_in_website>
30
+ <show_in_store>1</show_in_store>
31
+ <groups>
32
+ <search translate="label">
33
+ <label>FACT-Finder Access Data</label>
34
+ <frontend_type>text</frontend_type>
35
+ <sort_order>10</sort_order>
36
+ <show_in_default>1</show_in_default>
37
+ <show_in_website>1</show_in_website>
38
+ <show_in_store>1</show_in_store>
39
+ <fields>
40
+ <enabled translate="label">
41
+ <label>Enabled</label>
42
+ <frontend_type>select</frontend_type>
43
+ <source_model>adminhtml/system_config_source_yesno</source_model>
44
+ <backend_model>factfinder/system_config_backend_enabled</backend_model>
45
+ <show_in_default>1</show_in_default>
46
+ <show_in_website>1</show_in_website>
47
+ <show_in_store>1</show_in_store>
48
+ </enabled>
49
+ <address translate="label">
50
+ <label>Server URL</label>
51
+ <frontend_type>text</frontend_type>
52
+ <sort_order>20</sort_order>
53
+ <show_in_default>1</show_in_default>
54
+ <show_in_website>1</show_in_website>
55
+ <show_in_store>1</show_in_store>
56
+ </address>
57
+ <port translate="label">
58
+ <label>Server Port</label>
59
+ <frontend_type>text</frontend_type>
60
+ <sort_order>30</sort_order>
61
+ <show_in_default>1</show_in_default>
62
+ <show_in_website>1</show_in_website>
63
+ <show_in_store>1</show_in_store>
64
+ </port>
65
+ <context translate="label comment">
66
+ <label>Context Name</label>
67
+ <comment>Name of the FACT-Finder application</comment>
68
+ <frontend_type>text</frontend_type>
69
+ <sort_order>40</sort_order>
70
+ <show_in_default>1</show_in_default>
71
+ <show_in_website>1</show_in_website>
72
+ <show_in_store>1</show_in_store>
73
+ </context>
74
+ <auth_user translate="label comment">
75
+ <label>User Name</label>
76
+ <comment>User name for authentication</comment>
77
+ <frontend_type>text</frontend_type>
78
+ <sort_order>50</sort_order>
79
+ <show_in_default>1</show_in_default>
80
+ <show_in_website>1</show_in_website>
81
+ <show_in_store>1</show_in_store>
82
+ </auth_user>
83
+ <auth_password translate="label">
84
+ <label>Password</label>
85
+ <frontend_type>password</frontend_type>
86
+ <sort_order>60</sort_order>
87
+ <show_in_default>1</show_in_default>
88
+ <show_in_website>1</show_in_website>
89
+ <show_in_store>1</show_in_store>
90
+ </auth_password>
91
+ <channel translate="label comment">
92
+ <label>Channel</label>
93
+ <comment>FACT-Finder can provide multiple search indexes, each represented by a "channel". Leave empty to use the default channel.</comment>
94
+ <frontend_type>text</frontend_type>
95
+ <sort_order>70</sort_order>
96
+ <show_in_default>1</show_in_default>
97
+ <show_in_website>1</show_in_website>
98
+ <show_in_store>1</show_in_store>
99
+ </channel>
100
+ <language translate="label comment">
101
+ <label>Language</label>
102
+ <comment>Some text strings come directly from FACT-Finder. Enter the language code here. Leave empty to use the language specified by the user's browser.</comment>
103
+ <frontend_type>text</frontend_type>
104
+ <sort_order>80</sort_order>
105
+ <show_in_default>1</show_in_default>
106
+ <show_in_website>1</show_in_website>
107
+ <show_in_store>1</show_in_store>
108
+ </language>
109
+ <auth_type translate="label">
110
+ <label>Authentication Type</label>
111
+ <frontend_type>select</frontend_type>
112
+ <source_model>factfinder/system_config_source_authtype</source_model>
113
+ <sort_order>90</sort_order>
114
+ <show_in_default>1</show_in_default>
115
+ <show_in_website>1</show_in_website>
116
+ <show_in_store>1</show_in_store>
117
+ </auth_type>
118
+ <auth_advancedPrefix translate="label comment">
119
+ <label>Advanced Authentication Prefix</label>
120
+ <frontend_type>text</frontend_type>
121
+ <comment>The advanced authentication post- and prefix are only used when the authentication type is "advanced".</comment>
122
+ <sort_order>100</sort_order>
123
+ <show_in_default>1</show_in_default>
124
+ <show_in_website>1</show_in_website>
125
+ <show_in_store>1</show_in_store>
126
+ </auth_advancedPrefix>
127
+ <auth_advancedPostfix>
128
+ <label>Advanced Authentication Postfix</label>
129
+ <frontend_type>text</frontend_type>
130
+ <sort_order>110</sort_order>
131
+ <show_in_default>1</show_in_default>
132
+ <show_in_website>1</show_in_website>
133
+ <show_in_store>1</show_in_store>
134
+ </auth_advancedPostfix>
135
+ </fields>
136
+ </search>
137
+ <export translate="label">
138
+ <label>FACT-Finder Export Configuration</label>
139
+ <frontend_type>text</frontend_type>
140
+ <sort_order>20</sort_order>
141
+ <show_in_default>1</show_in_default>
142
+ <show_in_website>1</show_in_website>
143
+ <show_in_store>1</show_in_store>
144
+ <fields>
145
+ <urls translate="label">
146
+ <label>Export Images and Deeplinks</label>
147
+ <frontend_type>select</frontend_type>
148
+ <source_model>adminhtml/system_config_source_yesno</source_model>
149
+ <sort_order>10</sort_order>
150
+ <show_in_default>1</show_in_default>
151
+ <show_in_website>1</show_in_website>
152
+ <show_in_store>1</show_in_store>
153
+ </urls>
154
+ <clicktracking translate="label">
155
+ <label>Track product-clicks</label>
156
+ <frontend_type>select</frontend_type>
157
+ <source_model>adminhtml/system_config_source_yesno</source_model>
158
+ <sort_order>20</sort_order>
159
+ <show_in_default>1</show_in_default>
160
+ <show_in_website>1</show_in_website>
161
+ <show_in_store>1</show_in_store>
162
+ </clicktracking>
163
+ <track_carts translate="label">
164
+ <label>Track "Add to cart" events</label>
165
+ <frontend_type>select</frontend_type>
166
+ <source_model>adminhtml/system_config_source_yesno</source_model>
167
+ <sort_order>30</sort_order>
168
+ <show_in_default>1</show_in_default>
169
+ <show_in_website>1</show_in_website>
170
+ <show_in_store>1</show_in_store>
171
+ </track_carts>
172
+ <track_checkout translate="label">
173
+ <label>Track checkout</label>
174
+ <frontend_type>select</frontend_type>
175
+ <source_model>adminhtml/system_config_source_yesno</source_model>
176
+ <sort_order>40</sort_order>
177
+ <show_in_default>1</show_in_default>
178
+ <show_in_website>1</show_in_website>
179
+ <show_in_store>1</show_in_store>
180
+ </track_checkout>
181
+ <attributes translate="label">
182
+ <label>Attributes</label>
183
+ <frontend_model>factfinder/adminhtml_form_field_attributes</frontend_model>
184
+ <backend_model>factfinder/system_config_backend_attributes</backend_model>
185
+ <sort_order>50</sort_order>
186
+ <show_in_default>0</show_in_default>
187
+ <show_in_website>0</show_in_website>
188
+ <show_in_store>1</show_in_store>
189
+ </attributes>
190
+ </fields>
191
+ </export>
192
+ <config translate="label">
193
+ <label>FACT-Finder Config Data</label>
194
+ <frontend_type>text</frontend_type>
195
+ <sort_order>30</sort_order>
196
+ <show_in_default>1</show_in_default>
197
+ <show_in_website>1</show_in_website>
198
+ <show_in_store>1</show_in_store>
199
+ <fields>
200
+ <identifier translate="label">
201
+ <label>Product Identifier</label>
202
+ <frontend_type>select</frontend_type>
203
+ <source_model>factfinder/system_config_source_identifier</source_model>
204
+ <sort_order>10</sort_order>
205
+ <show_in_default>1</show_in_default>
206
+ <show_in_website>1</show_in_website>
207
+ <show_in_store>1</show_in_store>
208
+ </identifier>
209
+ <redirectOnSingleResult>
210
+ <label>Redirect to product page if single result</label>
211
+ <frontend_type>select</frontend_type>
212
+ <source_model>adminhtml/system_config_source_yesno</source_model>
213
+ <sort_order>20</sort_order>
214
+ <show_in_default>1</show_in_default>
215
+ <show_in_website>1</show_in_website>
216
+ <show_in_store>1</show_in_store>
217
+ </redirectOnSingleResult>
218
+ <proxy translate="label">
219
+ <label>Use Proxy for Suggest</label>
220
+ <frontend_type>select</frontend_type>
221
+ <source_model>adminhtml/system_config_source_yesno</source_model>
222
+ <sort_order>30</sort_order>
223
+ <show_in_default>1</show_in_default>
224
+ <show_in_website>1</show_in_website>
225
+ <show_in_store>1</show_in_store>
226
+ </proxy>
227
+ <internal_ip translate="label">
228
+ <label>Internal IPs</label>
229
+ <comment>Enter your internal ip addresses. Multiple ip addresses can be entered divided by semicolon.</comment>
230
+ <frontend_type>text</frontend_type>
231
+ <sort_order>40</sort_order>
232
+ <show_in_default>1</show_in_default>
233
+ <show_in_website>1</show_in_website>
234
+ <show_in_store>1</show_in_store>
235
+ </internal_ip>
236
+ <debug translate="label">
237
+ <label>Debug Log</label>
238
+ <frontend_type>select</frontend_type>
239
+ <source_model>adminhtml/system_config_source_yesno</source_model>
240
+ <sort_order>50</sort_order>
241
+ <show_in_default>1</show_in_default>
242
+ <show_in_website>1</show_in_website>
243
+ <show_in_store>1</show_in_store>
244
+ </debug>
245
+ </fields>
246
+ </config>
247
+ <activation translate="label">
248
+ <label>FACT-Finder Module Activation</label>
249
+ <frontend_type>text</frontend_type>
250
+ <sort_order>40</sort_order>
251
+ <show_in_default>1</show_in_default>
252
+ <show_in_website>1</show_in_website>
253
+ <show_in_store>1</show_in_store>
254
+ <fields>
255
+ <suggest translate="label">
256
+ <label>Use FACT-Finder Suggest Functionality</label>
257
+ <frontend_type>select</frontend_type>
258
+ <source_model>adminhtml/system_config_source_yesno</source_model>
259
+ <sort_order>10</sort_order>
260
+ <show_in_default>1</show_in_default>
261
+ <show_in_website>1</show_in_website>
262
+ <show_in_store>1</show_in_store>
263
+ </suggest>
264
+ <campaign translate="label">
265
+ <label>Use FACT-Finder Campaign Functionality</label>
266
+ <frontend_type>select</frontend_type>
267
+ <source_model>adminhtml/system_config_source_yesno</source_model>
268
+ <sort_order>20</sort_order>
269
+ <show_in_default>1</show_in_default>
270
+ <show_in_website>1</show_in_website>
271
+ <show_in_store>1</show_in_store>
272
+ </campaign>
273
+ <asn translate="label">
274
+ <label>Use FACT-Finder After Search Navigation Functionality</label>
275
+ <frontend_type>select</frontend_type>
276
+ <source_model>adminhtml/system_config_source_yesno</source_model>
277
+ <sort_order>30</sort_order>
278
+ <show_in_default>1</show_in_default>
279
+ <show_in_website>1</show_in_website>
280
+ <show_in_store>1</show_in_store>
281
+ </asn>
282
+ <navigation translate="label">
283
+ <label>Use FACT-Finder for Layered Navigation</label>
284
+ <frontend_type>select</frontend_type>
285
+ <source_model>adminhtml/system_config_source_yesno</source_model>
286
+ <sort_order>50</sort_order>
287
+ <show_in_default>1</show_in_default>
288
+ <show_in_website>1</show_in_website>
289
+ <show_in_store>1</show_in_store>
290
+ </navigation>
291
+ <upsell translate="label">
292
+ <label>Use FACT-Finder for Product Upsells</label>
293
+ <frontend_type>select</frontend_type>
294
+ <source_model>adminhtml/system_config_source_yesno</source_model>
295
+ <sort_order>60</sort_order>
296
+ <show_in_default>1</show_in_default>
297
+ <show_in_website>1</show_in_website>
298
+ <show_in_store>1</show_in_store>
299
+ </upsell>
300
+ <crosssell translate="label">
301
+ <label>Use FACT-Finder for Product Crosssells</label>
302
+ <frontend_type>select</frontend_type>
303
+ <source_model>adminhtml/system_config_source_yesno</source_model>
304
+ <sort_order>70</sort_order>
305
+ <show_in_default>1</show_in_default>
306
+ <show_in_website>1</show_in_website>
307
+ <show_in_store>1</show_in_store>
308
+ </crosssell>
309
+ <tagcloud translate="label">
310
+ <label>Use FACT-Finder for tag cloud computation</label>
311
+ <frontend_type>select</frontend_type>
312
+ <source_model>adminhtml/system_config_source_yesno</source_model>
313
+ <sort_order>80</sort_order>
314
+ <show_in_default>1</show_in_default>
315
+ <show_in_website>1</show_in_website>
316
+ <show_in_store>1</show_in_store>
317
+ </tagcloud>
318
+ </fields>
319
+ </activation>
320
+ </groups>
321
+ </factfinder>
322
+ </sections>
323
+ </config>
app/code/community/Flagbit/FactFinder/sql/factfinder_setup/mysql4-install-3.2.0.php ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Install script
12
+ *
13
+ * Install script for SCIC queue. Orders are sent to FACT-Finder asynchronously by cronjobs.
14
+ *
15
+ * @category Mage
16
+ * @package Flagbit_FactFinder
17
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
18
+ * @author Michael Türk <tuerk@flagbit.de>
19
+ * @version $Id: Processor.php 647 2011-03-21 10:32:14Z rudolf_batt $
20
+ */
21
+
22
+ $installer = $this;
23
+ $installer->startSetup();
24
+
25
+ $installer->run("
26
+ CREATE TABLE `{$installer->getTable('factfinder/scic_queue')}` (
27
+ `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT ,
28
+ `product_id` varchar(64) NOT NULL DEFAULT '',
29
+ `sid` varchar(32) NOT NULL DEFAULT '',
30
+ `userid` varchar(32) NOT NULL DEFAULT '',
31
+ `price` decimal(12,4) NOT NULL default '0.0000',
32
+ `count` smallint(5) unsigned NOT NULL default '1',
33
+
34
+ PRIMARY KEY (`id`)
35
+ ) ENGINE = InnoDB ;
36
+ ");
37
+
38
+ $installer->endSetup();
app/code/community/Flagbit/FactFinder/sql/factfinder_setup/mysql4-upgrade-3.2.0-3.2.1.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Install script
12
+ *
13
+ * Install script for SCIC queue. Orders are sent to FACT-Finder asynchronously by cronjobs.
14
+ *
15
+ * @category Mage
16
+ * @package Flagbit_FactFinder
17
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
18
+ * @author Michael Türk <tuerk@flagbit.de>
19
+ * @version $Id: Processor.php 647 2011-03-21 10:32:14Z rudolf_batt $
20
+ */
21
+
22
+ $installer = $this;
23
+ $installer->startSetup();
24
+
25
+ $installer->run("
26
+ ALTER TABLE `{$installer->getTable('factfinder/scic_queue')}`
27
+ ADD COLUMN `store_id` INT(10) UNSIGNED NOT NULL DEFAULT '0';
28
+ ");
29
+
30
+ $installer->endSetup();
app/code/community/Flagbit/FactFinder/sql/factfinder_setup/mysql4-upgrade-3.2.1-3.3.0.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Install script
12
+ *
13
+ * Update configuration keys
14
+ *
15
+ * @category Mage
16
+ * @package Flagbit_FactFinder
17
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
18
+ * @author Michael Türk <tuerk@flagbit.de>
19
+ * @version $Id: Processor.php 647 2011-03-21 10:32:14Z rudolf_batt $
20
+ */
21
+
22
+ $installer = $this;
23
+ $installer->startSetup();
24
+
25
+ $installer->run("
26
+ UPDATE `{$installer->getTable('core/config_data')}`
27
+ SET `path` = 'factfinder/activation/navigation' where `path` = 'factfinder/config/navigation';
28
+ UPDATE `{$installer->getTable('core/config_data')}`
29
+ SET `path` = 'factfinder/activation/upsell' where `path` = 'factfinder/config/upsell';
30
+ UPDATE `{$installer->getTable('core/config_data')}`
31
+ SET `path` = 'factfinder/activation/crosssell' where `path` = 'factfinder/config/crosssell';
32
+ ");
33
+
34
+ $installer->endSetup();
app/design/adminhtml/default/default/layout/factfinder.xml ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <!--
3
+ /**
4
+ * Flagbit_FactFinder
5
+ *
6
+ * @category Mage
7
+ * @package Flagbit_FactFinder
8
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
9
+ */
10
+
11
+ /**
12
+ * Module Layout Config
13
+ *
14
+ * @category Mage
15
+ * @package Flagbit_FactFinder
16
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
17
+ * @author Joerg Weller <weller@flagbit.de>
18
+ * @version $Id$
19
+ */
20
+ -->
21
+
22
+ <layout>
23
+ <adminhtml_factfinder_cockpit_index>
24
+ <reference name="content">
25
+ <block type="factfinder/adminhtml_cockpit" name="factfinder_cockpit" template="factfinder/cockpit.phtml"/>
26
+ </reference>
27
+ </adminhtml_factfinder_cockpit_index>
28
+ </layout>
app/design/adminhtml/default/default/template/factfinder/cockpit.phtml ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Template
12
+ *
13
+ * Business User Cockpit Template
14
+ *
15
+ * @category Mage
16
+ * @package Flagbit_FactFinder
17
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
18
+ * @author Joerg Weller <weller@flagbit.de>
19
+ * @version $Id$
20
+ */
21
+ ?>
22
+ <iframe src="<?php echo $this->getAuthenticationUrl();?>" id="factfinder_cockpit_frame" style="width:100%; height:600px;" name="factfinder_cockpit_frame" scrolling="auto"></iframe>
app/design/frontend/base/default/layout/factfinder.xml ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <!--
3
+ /**
4
+ * Flagbit_FactFinder
5
+ *
6
+ * @category Mage
7
+ * @package Flagbit_FactFinder
8
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
9
+ */
10
+
11
+ /**
12
+ * Module Layout Config
13
+ *
14
+ * @category Mage
15
+ * @package Flagbit_FactFinder
16
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
17
+ * @author Joerg Weller <weller@flagbit.de>
18
+ * @version $Id$
19
+ */
20
+ -->
21
+ <layout version="0.1.0">
22
+
23
+ <factfinder_suggest_enabled>
24
+ <reference name="top.search">
25
+ <action method="setTemplate"><template>factfinder/form.mini.phtml</template></action>
26
+ </reference>
27
+ <reference name="head">
28
+ <action method="addJs"><script>factfinder/jXHR.js</script></action>
29
+ <action method="addJs"><script>factfinder/suggest.js</script></action>
30
+ </reference>
31
+ </factfinder_suggest_enabled>
32
+
33
+ <catalogsearch_result_index>
34
+ <reference name="content">
35
+ <block type="factfinder/campaign_feedback" before="search.result" name="factfinder.campaign.feedback" template="factfinder/campaign/feedback.phtml">
36
+ <action method="setTextNumber"><number>1</number></action>
37
+ </block>
38
+ <block type="factfinder/campaign_advisory" after="factfinder.campaign.feedback" template="factfinder/campaign/advisory.phtml" />
39
+ <block type="core/template" name="factfinder.logo" template="factfinder/logo.phtml"/>
40
+ </reference>
41
+ </catalogsearch_result_index>
42
+
43
+ <catalog_product_view>
44
+ <reference name="content">
45
+ <!-- <block type="factfinder/campaign_product_advisory" before="product.info" template="factfinder/campaign/product/advisory.phtml" /-->
46
+ <block type="factfinder/campaign_product_feedback" before="product.info" template="factfinder/campaign/product/feedback.phtml" />
47
+ </reference>
48
+ <reference>
49
+ <block name="product.info.upsell">
50
+ <action method="setItemLimit"><type>upsell</type><limit>20</limit></action>
51
+ </block>
52
+ </reference>
53
+ </catalog_product_view>
54
+
55
+ <checkout_cart_index>
56
+ <reference name="checkout.cart.form.before">
57
+ <!-- <block type="factfinder/campaign_cart_advisory" before="-" template="factfinder/campaign/cart/advisory.phtml" /-->
58
+ <block type="factfinder/campaign_cart_feedback" before="-" template="factfinder/campaign/cart/feedback.phtml" />
59
+ </reference>
60
+ </checkout_cart_index>
61
+
62
+ <factfinder_clicktracking_enabled>
63
+ <reference name="head">
64
+ <action method="addJs"><script>factfinder/scic.js</script></action>
65
+ </reference>
66
+ <reference name="content">
67
+ <block type="factfinder/scic" name="factfinder.scic" template="factfinder/scic.phtml"/>
68
+ </reference>
69
+ </factfinder_clicktracking_enabled>
70
+ </layout>
app/design/frontend/base/default/template/factfinder/campaign/advisory.phtml ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php if ($questions = $this->getActiveQuestions()): ?>
2
+ <?php foreach ($questions as $question): ?>
3
+ <div class="factfinder-advisorCampaign">
4
+ <p class="factfinder-advisorCampaign-question"><?php echo $question->getText() ?></p>
5
+ <p>
6
+ <?php foreach ($question->getAnswers() as $answer): ?>
7
+ <a class="factfinder-advisorCampaign-answer" href="<?php echo $answer->getParams() ?>"><?php echo $answer->getText() ?></a>
8
+ <?php endforeach; ?>
9
+ </p>
10
+ </div>
11
+ <?php endforeach; ?>
12
+ <?php endif; ?>
app/design/frontend/base/default/template/factfinder/campaign/cart/advisory.phtml ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php if ($questions = $this->getActiveQuestions()): ?>
2
+ <?php foreach ($questions as $question): ?>
3
+ <div class="factfinder-advisorCampaign">
4
+ <p class="factfinder-advisorCampaign-question"><?php echo $question->getText() ?></p>
5
+ <p>
6
+ <?php foreach ($question->getAnswers() as $answer): ?>
7
+ <a class="factfinder-advisorCampaign-answer" href="<?php echo $answer->getParams() ?>"><?php echo $answer->getText() ?></a>
8
+ <?php endforeach; ?>
9
+ </p>
10
+ </div>
11
+ <?php endforeach; ?>
12
+ <?php endif; ?>
app/design/frontend/base/default/template/factfinder/campaign/cart/feedback.phtml ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <?php if ($feedback = $this->getActiveFeedback()): ?>
2
+ <?php $feedbackIds = array(0,1); ?>
3
+ <?php foreach ($feedbackIds as $feedbackId): ?>
4
+ <p class="factfinder-feedbackCampaign"><?php echo $feedback->getFeedback($feedbackId) ?></p>
5
+ <?php endforeach; ?>
6
+ <?php endif; ?>
app/design/frontend/base/default/template/factfinder/campaign/feedback.phtml ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php if(Mage::helper('factfinder/search')->getIsEnabled()):?>
2
+ <div class="ffcampaigntext"><?php echo $this->getText(); ?></div>
3
+
4
+ <?php
5
+ // this is an example, how to use the pushed products
6
+ $pushedProducts = $this->getPushedProductsCollection()->load()->toArray();
7
+ if (!empty($pushedProducts)) {
8
+ //customize here the pushed products output
9
+ echo ' <!-- ';
10
+ var_dump($pushedProducts);
11
+ echo ' --> ';
12
+ }
13
+ ?>
14
+ <?php endif;?>
app/design/frontend/base/default/template/factfinder/filter/slider.phtml ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Slider HTML Template
12
+ *
13
+ * @category Mage
14
+ * @package Flagbit_FactFinder
15
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
16
+ * @author Joerg Weller <weller@flagbit.de>
17
+ * @version $Id$
18
+ */
19
+ ?>
20
+ <ol>
21
+ <?php foreach ($this->getItems() as $_item): ?>
22
+ <li>
23
+ <div id="<?php echo base64_encode($this->getValue());?>" style="width: 170px;padding:10px 0px;"></div>
24
+ <script type="text/javascript" language="javascript">
25
+ //<![CDATA[
26
+
27
+ Event.observe(document, 'ffslider:init', function(event){
28
+ oneTouchSlider.addSlider({
29
+ hostElementId:'<?php echo base64_encode($this->getValue());?>',
30
+ leftBorder: <?php echo $this->getAbsoluteMin();?>,
31
+ rightBorder: <?php echo $this->getAbsoluteMax();?>,
32
+ currentLeft: <?php echo $this->getSelectedMin();?>,
33
+ currentRight: <?php echo $this->getSelectedMax();?>,
34
+ unit:"<?php echo $this->getUnit();?>",
35
+ callback:function(left, right){
36
+ var url = decodeURI('<?php echo $_item->getUrl() ?>');
37
+ window.location.href= url.replace('[VALUE]',left + '+-+' + right);
38
+ }
39
+ });
40
+ }
41
+ );
42
+ //]]>
43
+ </script>
44
+ </li>
45
+ <?php endforeach ?>
46
+ </ol>
app/design/frontend/base/default/template/factfinder/form.mini.phtml ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Template to replace Javascript Suguest
12
+ *
13
+ * @category Mage
14
+ * @package Flagbit_FactFinder
15
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
16
+ * @author Joerg Weller <weller@flagbit.de>
17
+ * @version $Id$
18
+ */
19
+ ?>
20
+ <form id="search_mini_form" action="<?php echo $this->helper('catalogsearch')->getResultUrl() ?>" method="get">
21
+ <div class="form-search">
22
+ <label for="search"><?php echo $this->__('Search:') ?></label>
23
+ <input id="search" type="text" name="<?php echo $this->helper('catalogsearch')->getQueryParamName() ?>" value="<?php echo $this->helper('catalogsearch')->getEscapedQueryText() ?>" class="input-text" />
24
+ <button type="submit" title="<?php echo $this->__('Search') ?>" class="button"><span><span><?php echo $this->__('Search') ?></span></span></button>
25
+ <div id="search_autocomplete" class="search-autocomplete"></div>
26
+ <script type="text/javascript">
27
+ //<![CDATA[
28
+ <?php if (Mage::helper('factfinder/search')->getIsEnabled(false, 'suggest')):?>
29
+ var searchForm = new FactFinderSuggest('search_mini_form', 'search', '<?php echo $this->__('Search entire store here...') ?>');
30
+ searchForm.initAutocomplete('<?php echo $this->helper('factfinder/search')->getSuggestUrl() ?>', 'search_autocomplete');
31
+ <?php else:?>
32
+ var searchForm = new Varien.searchForm('search_mini_form', 'search', '<?php echo $this->__('Search entire store here...') ?>');
33
+ searchForm.initAutocomplete('<?php echo $this->helper('catalogsearch')->getSuggestUrl() ?>', 'search_autocomplete');
34
+ <?php endif;?>
35
+ //]]>
36
+ </script>
37
+ </div>
38
+ </form>
app/design/frontend/base/default/template/factfinder/logo.phtml ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Add FACT-Finder Logo to Search Result
12
+ *
13
+ * @category Mage
14
+ * @package Flagbit_FactFinder
15
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
16
+ * @author Joerg Weller <weller@flagbit.de>
17
+ * @version $Id$
18
+ */
19
+ ?>
20
+ <?php if(Mage::helper('factfinder/search')->getIsEnabled()):?>
21
+ <div style="text-align:center;margin: 10px auto;"><a href="http://www.fact-finder.de"><img src="http://www.fact-finder.de/files/fact_finder_conversion.jpg" border="0" alt="on-site search & navigation – conversion engine FACT-Finder" target="_blank" width="116" height="35"></a></div>
22
+ <?php endif;?>
app/design/frontend/base/default/template/factfinder/scic.phtml ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Flagbit_FactFinder
4
+ *
5
+ * @category Mage
6
+ * @package Flagbit_FactFinder
7
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
8
+ */
9
+
10
+ /**
11
+ * Add FACT-Finder SCIC
12
+ *
13
+ * @category Mage
14
+ * @package Flagbit_FactFinder
15
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
16
+ * @author Joerg Weller <weller@flagbit.de>
17
+ * @version $Id$
18
+ */
19
+ ?>
20
+ <script type="text/javascript">
21
+ var factfinderSCIC = new FactfinderSCIC(
22
+ '.col-main',
23
+ $H(<?php echo $this->getJsonDataObject();?>),
24
+ $H(<?php echo $this->getJsonUrlToIdMappingObject();?>),
25
+ '<?php echo $this->getUrl('factfinder/proxy/scic'); ?>'
26
+ );
27
+
28
+ Event.observe(document, 'dom:loaded', function(event) {
29
+ factfinderSCIC.init();
30
+ });
31
+ </script>
app/etc/factfinder.xml ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version='1.0' encoding="utf-8" ?>
2
+ <!--
3
+ /**
4
+ * Flagbit_FactFinder
5
+ *
6
+ * @category Mage
7
+ * @package Flagbit_FactFinder
8
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
9
+ */
10
+
11
+ /**
12
+ * Module Config
13
+ *
14
+ * @category Mage
15
+ * @package Flagbit_FactFinder
16
+ * @copyright Copyright (c) 2010 Flagbit GmbH & Co. KG (http://www.flagbit.de/)
17
+ * @author Joerg Weller <weller@flagbit.de>
18
+ * @version $Id$
19
+ */
20
+ -->
21
+ <config>
22
+ <global>
23
+ <cache>
24
+ <request_processors>
25
+ <factfinder>Flagbit_FactFinder_Model_Processor</factfinder>
26
+ </request_processors>
27
+ </cache>
28
+ </global>
29
+ </config>
app/etc/modules/Flagbit_FactFinder.xml ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <Flagbit_FactFinder>
5
+ <active>true</active>
6
+ <codePool>community</codePool>
7
+ </Flagbit_FactFinder>
8
+ </modules>
9
+ </config>
app/locale/de_DE/Flagbit_FactFinder.csv ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "advanced", "fortgeschritten"
2
+ "Advanced Authentication Postfix", "Suffix für fortgeschrittene Authentifizierung"
3
+ "Advanced Authentication Prefix", "Präfix für fortgeschrittene Authentifizierung"
4
+ "Authentication Type", "Authentifizierungstyp"
5
+ "Catalog", "Katalog"
6
+ "Channel", "Channel"
7
+ "Context Name", "Kontext-Name"
8
+ "Debug Log", "Debug Log"
9
+ "Enabled", "Aktiviert"
10
+ "Enter your internal ip addresses. Multiple ip addresses can be entered divided by semicolon.", "Geben Sie hier Ihre internen IP-Adressen ein. Mehrere IP-Adressen werden mit Semikolon getrennt."
11
+ "Export Images and Deeplinks", "Bilder und Deeplinks exportieren"
12
+ "FACT-Finder", "FACT-Finder"
13
+ "FACT-Finder Access Data", "FACT-Finder Zugangsdaten"
14
+ "FACT-Finder Business User Cockpit", "FACT-Finder Business User Cockpit"
15
+ "FACT-Finder can provide multiple search indexes, each represented by a ""channel"". Leave empty to use the default channel.", "FACT-Finder kann mehrere Such-Indizes zur Verfügung stellen. Jeder Index wird durch einen ""Channel"" dargestellt. Wenn kein Wert angegeben ist, wird der Standard-Channel genutzt."
16
+ "FACT-Finder cannot be activated:", "FACT-Finder konnte nicht aktiviert werden:"
17
+ "FACT-Finder Config Data", "FACT-Finder Konfigurationsdaten"
18
+ "FACT-Finder Export Configuration", "FACT-Finder Export-Konfiguration"
19
+ "FACT-Finder Status", "FACT-Finder Status"
20
+ "http", "http"
21
+ "Internal IPs", "Interne IPs"
22
+ "Language", "Sprache"
23
+ "Name of the FACT-Finder application", "Name der FACT-Finder-Applikation"
24
+ "No", "Nein"
25
+ "Password", "Passwort"
26
+ "Product ID (default)", "Produkt-ID (Standard)"
27
+ "Product Identifier", "Produkt Identifizierung"
28
+ "Product SKU", "Produkt-SKU (Artikelnummer)"
29
+ "Redirect to product page if single result", "Bei eindeutigem Resultat auf Produkt-Detailseite weiterleiten"
30
+ "Search", "Suche"
31
+ "Search entire store here...", "Den gesamten Shop durchsuchen..."
32
+ "Search:", "Suche:"
33
+ "Server Port", "Servers-Port"
34
+ "Server URL", "Server-URL"
35
+ "servername should only contain the IP address or the domain - no ""http://"" or any slashes!", "Der Servername sollte ausschließlih die IP-Adresse oder die Domain enthalten - kein ""http://"" und keine Slashes (\)!"
36
+ "simple", "einfach"
37
+ "Some text strings come directly from FACT-Finder. Enter the language code here. Leave empty to use the language specified by the user's browser.", "Einige Texte kommen direkt von FACT-Finder. Mit dem Sprach-Code in diesem Feld können Sie die Sprache festlegen. Bei leerem Wert erhält der Benutzer Labels in seiner angegebenen Browser-Sprache."
38
+ "The advanced authentication post- and prefix are only used when the authentication type is ""advanced"".", "Die Werte der Prä- und Suffixes werden ausschließlich bei fortgeschrittener Authentifizierung verwendet."
39
+ "the value for ""port"" must be numeric!", "Der Wert für den Server-Port muss numerisch sein!"
40
+ "the value for ""port"" must be a number greater or equals 80!", "Der Wert für den Server-Port muss größer oder gleich 80 sein!"
41
+ "There is a Class Rewrite Conflict: ""%s"" already overwritten by ""%s""", "Es besteht ein Klassen-Rewrite-Konflikt: ""%s"" wurde bereits durch ""%s"" überschrieben!"
42
+ "there must be a username, if a password should be used", "Sie müssen einen Benutzernamen verwenden."
43
+ "Track ""Add to cart"" events", "Warenkorb-Events tracken"
44
+ "Track checkout", "Verkaufte Produkte tracken"
45
+ "Use FACT-Finder for Layered Navigation", "FACT-Finder für Layered Navigation einsetzen"
46
+ "Use FACT-Finder for Product Crosssells", "FACT-Finder für Cross-Sells einsetzen"
47
+ "Use FACT-Finder for Product Upsells", "FACT-Finder für Upsells einsetzen"
48
+ "Use FACT-Finder for tag cloud computation", "FACT-Finder für die Berechnung der TagCloud verwenden"
49
+ "Use FACT-Finder Search", "FACT-Finder-Suche nutzen"
50
+ "Use Proxy for Suggest", "Proxy für Autovervollständigung nutzen"
51
+ "User Name", "Benutzername"
52
+ "User name for authentication", "Benutzername für Authentifizierung"
53
+ "Yes", "Ja"
54
+ "WARNING: was not able to connect to FACT-Finder.", "WARNUNG: Konnte nicht mit dem FACT-Finder-Server verbinden."
js/factfinder/jXHR.js ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // jXHR.js (JSON-P XHR)
2
+ // v0.1 (c) Kyle Simpson
3
+ // MIT License
4
+
5
+ (function(global){
6
+ var SETTIMEOUT = global.setTimeout, // for better compression
7
+ doc = global.document,
8
+ callback_counter = 0;
9
+
10
+ global.jXHR = function() {
11
+ var script_url,
12
+ script_loaded,
13
+ jsonp_callback,
14
+ scriptElem,
15
+ publicAPI = null;
16
+
17
+ function removeScript() { try { scriptElem.parentNode.removeChild(scriptElem); } catch (err) { } }
18
+
19
+ function reset() {
20
+ script_loaded = false;
21
+ script_url = "";
22
+ removeScript();
23
+ scriptElem = null;
24
+ fireReadyStateChange(0);
25
+ }
26
+
27
+ function ThrowError(msg) {
28
+ try { publicAPI.onerror.call(publicAPI,msg,script_url); } catch (err) { throw new Error(msg); }
29
+ }
30
+
31
+ function handleScriptLoad() {
32
+ if ((this.readyState && this.readyState!=="complete" && this.readyState!=="loaded") || script_loaded) { return; }
33
+ this.onload = this.onreadystatechange = null; // prevent memory leak
34
+ script_loaded = true;
35
+ if (publicAPI.readyState !== 4) ThrowError("Script failed to load ["+script_url+"].");
36
+ removeScript();
37
+ }
38
+
39
+ function fireReadyStateChange(rs,args) {
40
+ args = args || [];
41
+ publicAPI.readyState = rs;
42
+ if (typeof publicAPI.onreadystatechange === "function") publicAPI.onreadystatechange.apply(publicAPI,args);
43
+ }
44
+
45
+ publicAPI = {
46
+ onerror:null,
47
+ onreadystatechange:null,
48
+ readyState:0,
49
+ open:function(method,url){
50
+ reset();
51
+ internal_callback = "cb"+(callback_counter++);
52
+ (function(icb){
53
+ global.jXHR[icb] = function() {
54
+ try { fireReadyStateChange.call(publicAPI,4,arguments); }
55
+ catch(err) {
56
+ publicAPI.readyState = -1;
57
+ ThrowError("Script failed to run ["+script_url+"].");
58
+ }
59
+ global.jXHR[icb] = null;
60
+ };
61
+ })(internal_callback);
62
+ script_url = url.replace(/=\?/g,"=jXHR."+internal_callback);
63
+ fireReadyStateChange(1);
64
+ },
65
+ send:function(){
66
+ SETTIMEOUT(function(){
67
+ scriptElem = doc.createElement("script");
68
+ scriptElem.setAttribute("type","text/javascript");
69
+ scriptElem.onload = scriptElem.onreadystatechange = function(){handleScriptLoad.call(scriptElem);};
70
+ scriptElem.setAttribute("src",script_url);
71
+ doc.getElementsByTagName("head")[0].appendChild(scriptElem);
72
+ },0);
73
+ fireReadyStateChange(2);
74
+ },
75
+ setRequestHeader:function(){}, // noop
76
+ getResponseHeader:function(){return "";}, // basically noop
77
+ getAllResponseHeaders:function(){return [];} // ditto
78
+ };
79
+
80
+ reset();
81
+
82
+ return publicAPI;
83
+ };
84
+ })(window);
js/factfinder/scic.js ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ var FactfinderSCIC = Class.create({
2
+ url: null,
3
+ data: null,
4
+ classname: null,
5
+ mapping: null,
6
+ request: null,
7
+ regex: new RegExp(/product\/([0-9]+)\//),
8
+ initialize: function(classname, data, mapping, url) {
9
+ this.classname = classname;
10
+ this.data = data;
11
+ this.mapping = mapping;
12
+ this.url = url;
13
+ },
14
+
15
+ init: function() {
16
+ $$(this.classname+' a',this.classname+' button').each(function(element) {
17
+ this.mapping.each(function(pair, index) {
18
+ if(element.readAttribute('href') && element.readAttribute('href') == pair.key){
19
+ return this.prepareElement(element, pair.value, 'click');
20
+ }
21
+ if(element.readAttribute('onclick') && element.readAttribute('onclick').indexOf(pair.key) >= 0){
22
+ return this.prepareElement(element, pair.value, 'click');
23
+ }
24
+ }.bind(this));
25
+
26
+ if(element.readAttribute('href')) {
27
+ var match = this.regex.exec(element.readAttribute('href'));
28
+ if(match && match[1]) {
29
+ return this.prepareElement(element, match[1], 'click');
30
+ }
31
+ }
32
+
33
+ if(element.readAttribute('onclick')) {
34
+ var match = this.regex.exec(element.readAttribute('onclick'));
35
+ if(match && match[1]) {
36
+ return this.prepareElement(element, match[1], 'click');
37
+ }
38
+ }
39
+ }.bind(this));
40
+ },
41
+
42
+ prepareElement: function(element, id, eventType) {
43
+ Event.observe(element, 'click', function(event) {
44
+ this.recordRequest(id, eventType);
45
+ }.bind(this));
46
+ },
47
+
48
+ recordRequest: function(id, eventType) {
49
+
50
+ var data = this.data.get(id);
51
+ data.event = eventType;
52
+
53
+ this.request = new Ajax.Request(this.url, {
54
+ method: 'post',
55
+ parameters: data
56
+ });
57
+ return false;
58
+ }
59
+ });
js/factfinder/suggest.js ADDED
@@ -0,0 +1,185 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ var FactFinderAjax = {
2
+ getTransport: function() {
3
+ return new jXHR();
4
+ },
5
+
6
+ activeRequestCount: 0
7
+ };
8
+
9
+ FactFinderAjax.Response = Class.create(Ajax.Response, {
10
+
11
+ initialize: function(request){
12
+ this.request = request;
13
+ var transport = this.transport = request.transport,
14
+ readyState = this.readyState = transport.readyState;
15
+
16
+ if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) {
17
+ this.status = this.getStatus();
18
+ this.statusText = this.getStatusText();
19
+ this.responseText = String.interpret(transport.responseText);
20
+ this.headerJSON = this._getHeaderJSON();
21
+ }
22
+
23
+ if(readyState == 4) {
24
+ var xml = transport.responseXML;
25
+ this.responseXML = Object.isUndefined(xml) ? null : xml;
26
+ this.responseJSON = this._getResponseJSON();
27
+ }
28
+ }
29
+ });
30
+
31
+ FactFinderAjax.Request = Class.create(Ajax.Request, {
32
+ _complete: false,
33
+
34
+ initialize: function(url, options) {
35
+ this.options = {
36
+ method: 'get',
37
+ asynchronous: true,
38
+ contentType: 'application/x-www-form-urlencoded',
39
+ encoding: 'UTF-8',
40
+ parameters: '',
41
+ evalJSON: true,
42
+ evalJS: true
43
+ };
44
+ Object.extend(this.options, options || { });
45
+
46
+ this.options.method = this.options.method.toLowerCase();
47
+
48
+ if (Object.isString(this.options.parameters))
49
+ this.options.parameters = this.options.parameters.toQueryParams();
50
+ else if (Object.isHash(this.options.parameters))
51
+ this.options.parameters = this.options.parameters.toObject();
52
+
53
+ this.transport = FactFinderAjax.getTransport();
54
+ this.request(url);
55
+ },
56
+
57
+ request: function(url) {
58
+ this.url = url;
59
+ this.method = this.options.method;
60
+ var params = Object.clone(this.options.parameters);
61
+
62
+ if (!['get', 'post'].include(this.method)) {
63
+ // simulate other verbs over post
64
+ params['_method'] = this.method;
65
+ this.method = 'post';
66
+ }
67
+
68
+ this.parameters = params;
69
+
70
+ if (params = Object.toQueryString(params)) {
71
+ // when GET, append parameters to URL
72
+ if (this.method == 'get')
73
+ this.url += (this.url.include('?') ? '&' : '?') + params + '&jquery_callback=?&callback=?';
74
+ else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent))
75
+ params += '&_=';
76
+ }
77
+
78
+ try {
79
+
80
+ var response = new FactFinderAjax.Response(this);
81
+ if (this.options.onCreate) this.options.onCreate(response);
82
+ Ajax.Responders.dispatch('onCreate', this, response);
83
+
84
+ this.transport.open(this.method.toUpperCase(), this.url,
85
+ this.options.asynchronous);
86
+
87
+ if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1);
88
+
89
+ this.transport.onreadystatechange = this.onStateChange.bind(this);
90
+ this.setRequestHeaders();
91
+
92
+ this.body = this.method == 'post' ? (this.options.postBody || params) : null;
93
+ this.transport.send(this.body);
94
+
95
+ /* Force Firefox to handle ready state 4 for synchronous requests */
96
+ if (!this.options.asynchronous && this.transport.overrideMimeType)
97
+ this.onStateChange();
98
+
99
+ }
100
+ catch (e) {
101
+ this.dispatchException(e);
102
+ }
103
+ },
104
+
105
+ isSameOrigin: function() {
106
+ var m = this.url.match(/^\s*https?:\/\/[^\/]*/);
107
+ return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({
108
+ protocol: location.protocol,
109
+ domain: document.domain,
110
+ port: location.port ? ':' + location.port : ''
111
+ }));
112
+ }
113
+ });
114
+
115
+ var FactFinderAutocompleter = Class.create(Ajax.Autocompleter, {
116
+ caller: null,
117
+ rq: null,
118
+ getUpdatedChoices: function() {
119
+ this.startIndicator();
120
+
121
+ var entry = encodeURIComponent(this.options.paramName) + '=' +
122
+ encodeURIComponent(this.getToken());
123
+
124
+ this.options.parameters = this.options.callback ?
125
+ this.options.callback(this.element, entry) : entry;
126
+
127
+ if(this.options.defaultParams)
128
+ this.options.parameters += '&' + this.options.defaultParams;
129
+
130
+ this.rq = new FactFinderAjax.Request(this.url, this.options);
131
+ this.rq.transport.onreadystatechange = this.caller._loadData.bind(this.caller);
132
+ }
133
+ })
134
+
135
+ var FactFinderSuggest = Class.create(Varien.searchForm, {
136
+ request: null,
137
+
138
+ initAutocomplete : function(url, destinationElement){
139
+ this.request = new FactFinderAutocompleter(
140
+ this.field,
141
+ destinationElement,
142
+ url,
143
+ {
144
+ parameters: 'format=JSONP',
145
+ paramName: 'query',
146
+ method: 'get',
147
+ minChars: 2,
148
+ updateElement: this._selectAutocompleteItem.bind(this),
149
+ onShow : function(element, update) {
150
+ if(!update.style.position || update.style.position=='absolute') {
151
+ update.style.position = 'absolute';
152
+ Position.clone(element, update, {
153
+ setHeight: false,
154
+ offsetTop: element.offsetHeight
155
+ });
156
+ }
157
+ Effect.Appear(update,{duration:0});
158
+ }
159
+ }
160
+ );
161
+ this.request.caller = this;
162
+ },
163
+
164
+ _loadData: function(data) {
165
+ var content = '<ul>';
166
+ content += '<li style="display: none" class="selected"></li>';
167
+ data.each(function(item) {
168
+ var hitCount = item.hitCount == '0' ? '' : item.hitCount;
169
+ content += '<li title="'+item.query+'"><span class="amount">' + hitCount + '</span>' + item.query + '</li>';
170
+ });
171
+ content += '</ul>';
172
+
173
+ this.request.updateChoices(content);
174
+ },
175
+
176
+ _selectAutocompleteItem : function(element){
177
+ if(element.title){
178
+ this.form.insert('<input type="hidden" name="queryFromSuggest" value="true" />');
179
+ this.form.insert('<input type="hidden" name="userInput" value="'+this.field.value+'" />');
180
+
181
+ this.field.value = element.title;
182
+ }
183
+ this.form.submit();
184
+ }
185
+ });
lib/FACTFinder/Abstract/Adapter.php ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * handles the issue to create useable object from the data delivered by the dataprovider.
5
+ * this class can also be seen as a factory, but it is rather an adapter, because it converst the responded objects into
6
+ * the useable, unique objects
7
+ *
8
+ * @author Rudolf Batt <rb@omikron.net>
9
+ * @version $Id: Adapter.php 25893 2010-06-29 08:19:43Z rb $
10
+ * @package FACTFinder\Abstract
11
+ */
12
+ abstract class FACTFinder_Abstract_Adapter
13
+ {
14
+ protected $paramsParser;
15
+ protected $dataProvider;
16
+ protected $encodingHandler;
17
+
18
+ protected $log;
19
+
20
+ protected $data;
21
+
22
+ final public function __construct(FACTFinder_Abstract_DataProvider $dataProvider, FACTFinder_ParametersParser $paramsParser,
23
+ FACTFinder_EncodingHandler $encodingHandler)
24
+ {
25
+ $this->log = FF::getLogger();
26
+ $this->setDataProvider($dataProvider);
27
+ $this->setParamsParser($paramsParser);
28
+ $this->setEncodingHandler($encodingHandler);
29
+ $this->init();
30
+ }
31
+
32
+ /**
33
+ * can be overwritten to do initialising issues, that would normaly done by the constructor. it will be called at
34
+ * the end of the constructor
35
+ *
36
+ * @return void
37
+ */
38
+ protected function init(){}
39
+
40
+ /**
41
+ * returns the data lazily. if it isn't available yet, it will be requested from the dataprovider.
42
+ * decorates the dataprovider::getData method so a inheriting class does not have to use the dataprovider
43
+ */
44
+ protected function getData()
45
+ {
46
+ if(!isset($this->data)) {
47
+ $this->data = $this->getDataProvider()->getData();
48
+ }
49
+ return $this->data;
50
+ }
51
+
52
+ protected function reloadData()
53
+ {
54
+ $this->data = $this->getDataProvider()->getData();
55
+ return $this->data;
56
+ }
57
+
58
+ /**
59
+ * set data provider
60
+ *
61
+ * @param FACTFinder_Abstract_DataProvider
62
+ * @return void
63
+ **/
64
+ public function setDataProvider(FACTFinder_Abstract_DataProvider $dataProvider)
65
+ {
66
+ $this->dataProvider = $dataProvider;
67
+ }
68
+
69
+ /**
70
+ * get data provider
71
+ *
72
+ * @return FACTFinder_Abstract_DataProvider
73
+ **/
74
+ protected function getDataProvider()
75
+ {
76
+ return $this->dataProvider;
77
+ }
78
+
79
+ /**
80
+ * set parameter parser
81
+ *
82
+ * @param FACTFinder_ParametersParser $paramsParser
83
+ */
84
+ public function setParamsParser(FACTFinder_ParametersParser $paramsParser)
85
+ {
86
+ $this->paramsParser = $paramsParser;
87
+ }
88
+
89
+ /**
90
+ * returns the used factfinder params object.
91
+ *
92
+ * @return FACTFinder_ParametersParser
93
+ **/
94
+ protected function getParamsParser()
95
+ {
96
+ return $this->paramsParser;
97
+ }
98
+
99
+ /**
100
+ * set encoding handler
101
+ *
102
+ * @param FACTFinder_EncodingHandler $encodingHandler
103
+ */
104
+ public function setEncodingHandler(FACTFinder_EncodingHandler $encodingHandler)
105
+ {
106
+ $this->encodingHandler = $encodingHandler;
107
+ }
108
+
109
+ /**
110
+ * returns the used encoding handler
111
+ *
112
+ * @return FACTFinder_EncodingHandler
113
+ **/
114
+ protected function getEncodingHandler()
115
+ {
116
+ return $this->encodingHandler;
117
+ }
118
+ }
lib/FACTFinder/Abstract/CompareAdapter.php ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * adapter for the factfinder "product comparison" data
5
+ *
6
+ * @author Martin Buettner <martin.buettner@omikron.net>
7
+ * @version $Id: CompareAdapter.php 42955 2012-01-25 16:07:45Z mb $
8
+ * @package FACTFinder\Abstract
9
+ */
10
+ abstract class FACTFinder_Abstract_CompareAdapter extends FACTFinder_Abstract_Adapter
11
+ {
12
+ protected $productIds = array();
13
+
14
+ protected $comparableAttributes = array();
15
+ protected $comparedRecords = array();
16
+ protected $attributesUpToDate = false;
17
+ protected $recordsUpToDate = false;
18
+
19
+ protected $idsOnly = false;
20
+
21
+ /**
22
+ * Set ids of products to be compared
23
+ *
24
+ * @param array $productIds list of integers
25
+ **/
26
+ public function setProductIds($productIds) {
27
+ $this->productIds = $productIds;
28
+ $this->getDataProvider()->setParam('ids', implode(';',$this->productIds));
29
+ $this->attributesUpToDate = false;
30
+ $this->recordsUpToDate = false;
31
+ }
32
+
33
+ /**
34
+ * Set the idsOnly request parameter
35
+ *
36
+ * @param bool $idsOnly
37
+ **/
38
+ public function setIdsOnly($idsOnly) {
39
+ $this->idsOnly = $idsOnly;
40
+ $this->getDataProvider()->setParam('idsOnly', $idsOnly ? 'true' : 'false');
41
+ }
42
+
43
+ /**
44
+ * Adds an id to the list of products to be compared
45
+ *
46
+ * @param int $productId
47
+ **/
48
+ public function addProductId($productId) {
49
+ $this->productIds[] = $productId;
50
+ $this->attributesUpToDate = false;
51
+ $this->recordsUpToDate = false;
52
+ }
53
+
54
+ /**
55
+ * returns the comparable attributes for products to be compared
56
+ *
57
+ * @return array $comparableAttributes of strings (field names as keys, hasDifferences as values)
58
+ **/
59
+ public function getComparableAttributes() {
60
+ if (!$this->attributesUpToDate || !isset($this->comparableAttributes) || $this->comparableAttributes == null) {
61
+ $this->comparableAttributes = $this->createComparableAttributes();
62
+ $this->attributesUpToDate == true;
63
+ }
64
+ return $this->comparableAttributes;
65
+ }
66
+
67
+ /**
68
+ * returns the Record objects or record ids for products to be compared (depending on the value of idsOnly)
69
+ *
70
+ * @return array $comparedRecords list of FACTFinder_Record objects
71
+ **/
72
+ public function getComparedRecords() {
73
+ if (!$this->recordsUpToDate || !isset($this->comparedRecords) || $this->comparedRecords == null) {
74
+ $this->comparedRecords = $this->createComparedRecords();
75
+ $this->recordsUpToDate == true;
76
+ }
77
+ return $this->comparedRecords;
78
+ }
79
+
80
+ /**
81
+ * @return array $comparableAttributes of strings (field names as keys, hasDifferences as values)
82
+ */
83
+ abstract protected function createComparableAttributes();
84
+
85
+ /**
86
+ * @return array $comparedRecords list of FACTFinder_Record objects or integers (depending on the value of idsOnly)
87
+ */
88
+ abstract protected function createComparedRecords();
89
+ }
lib/FACTFinder/Abstract/Configuration.php ADDED
@@ -0,0 +1,153 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * interface to access the needed configuration values
5
+ *
6
+ * @category FACTFinderLib
7
+ * @package FACTFinder\Abstract
8
+ */
9
+ interface FACTFinder_Abstract_Configuration
10
+ {
11
+ /**
12
+ * @return string
13
+ */
14
+ function getVersion();
15
+
16
+ /**
17
+ * @param string name
18
+ * @return string value
19
+ */
20
+ function getCustomValue($name);
21
+
22
+ /**
23
+ * @return string
24
+ */
25
+ function getRequestProtocol();
26
+
27
+ /**
28
+ * @return string
29
+ */
30
+ function getServerAddress();
31
+
32
+ /**
33
+ * @return int
34
+ */
35
+ function getServerPort();
36
+
37
+ /**
38
+ * @return string
39
+ */
40
+ function getContext();
41
+
42
+ /**
43
+ * @return string
44
+ */
45
+ function getChannel();
46
+
47
+ /**
48
+ * @return string
49
+ */
50
+ function getLanguage();
51
+
52
+ /**
53
+ * @return string
54
+ */
55
+ function getAuthUser();
56
+
57
+ /**
58
+ * @return string
59
+ */
60
+ function getAuthPasswort();
61
+
62
+ /**
63
+ * @return boolean
64
+ */
65
+ function isHttpAuthenticationType();
66
+
67
+ /**
68
+ * @return boolean
69
+ */
70
+ function isSimpleAuthenticationType();
71
+
72
+ /**
73
+ * @return boolean
74
+ */
75
+ function isAdvancedAuthenticationType();
76
+
77
+ /**
78
+ * @return string
79
+ */
80
+ function getAdvancedAuthPrefix();
81
+
82
+ /**
83
+ * @return string
84
+ */
85
+ function getAdvancedAuthPostfix();
86
+
87
+ /**
88
+ * get mapping rules to map params for the page
89
+ *
90
+ * @return array
91
+ */
92
+ function getPageMappings();
93
+
94
+ /**
95
+ * get mapping rules to map params for the server
96
+ *
97
+ * @return array
98
+ */
99
+ function getServerMappings();
100
+
101
+ /**
102
+ * returns an array of parameter names as array keys with the boolean value true. this are the ignored page
103
+ * parameters from the configuration
104
+ *
105
+ * @return array with string as key and boolean true as value for each of them
106
+ */
107
+ function getIgnoredPageParams();
108
+
109
+ /**
110
+ * returns an array of parameter names as array keys with the boolean value true. this are the ignored server
111
+ * parameters from the configuration
112
+ *
113
+ * @return array with string as key and boolean true as value for each of them
114
+ */
115
+ function getIgnoredServerParams();
116
+
117
+ /**
118
+ * returns an array of the required parameters for the page. The array-keys are the parameter names and the array
119
+ * values are the default values of each parameter
120
+ *
121
+ * @return array string to string map (param-name as array-key; default value as array-value)
122
+ */
123
+ function getRequiredPageParams();
124
+
125
+ /**
126
+ * returns an array of the required parameters for the server. The array-keys are the parameter names and the array
127
+ * values are the default values of each parameter
128
+ *
129
+ * @return array string to string map (param-name as array-key; default value as array-value)
130
+ */
131
+ function getRequiredServerParams();
132
+
133
+ /**
134
+ * get encoding of the page content
135
+ *
136
+ * @return string
137
+ */
138
+ function getPageContentEncoding();
139
+
140
+ /**
141
+ * get encoding of the page url
142
+ *
143
+ * @return string
144
+ */
145
+ function getPageUrlEncoding();
146
+
147
+ /**
148
+ * get encoding of the server url
149
+ *
150
+ * @return string
151
+ */
152
+ function getServerUrlEncoding();
153
+ }
lib/FACTFinder/Abstract/DataProvider.php ADDED
@@ -0,0 +1,112 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * abstract data provider
5
+ *
6
+ * @author Rudolf Batt <rb@omikron.net>
7
+ * @version $Id: DataProvider.php 25893 2010-06-29 08:19:43Z rb $
8
+ * @package FACTFinder\Abstract
9
+ */
10
+ abstract class FACTFinder_Abstract_DataProvider
11
+ {
12
+ protected $params = array();
13
+ protected $config = array();
14
+ protected $type;
15
+
16
+ protected $log;
17
+
18
+ public function __construct(array $params = null, FACTFinder_Abstract_Configuration $config = null)
19
+ {
20
+ $this->log = FF::getLogger();
21
+ $this->log->info("Initializing data provider.");
22
+ if ($params != null) $this->setParams($params);
23
+ if ($config != null) $this->setConfig($config);
24
+ }
25
+
26
+ /**
27
+ * set type to identify which data should be loaded. that could be a request path or any source identifier
28
+ *
29
+ * @param mixed target
30
+ **/
31
+ public function setType($type)
32
+ {
33
+ $this->type = $type;
34
+ }
35
+
36
+ /**
37
+ * return the data for the current config and params; the return type depends on the implementation
38
+ *
39
+ * @return mixed data
40
+ **/
41
+ abstract public function getData();
42
+
43
+ /**
44
+ * sets factfinder params object
45
+ *
46
+ * @param array params
47
+ * @return void
48
+ **/
49
+ public function setParams(array $params)
50
+ {
51
+ $this->params = $params;
52
+ }
53
+
54
+ /**
55
+ * set single param
56
+ *
57
+ * @param string name
58
+ * @param string value
59
+ * @return void
60
+ **/
61
+ public function setParam($name, $value)
62
+ {
63
+ $this->params[$name] = $value;
64
+ }
65
+
66
+ /**
67
+ * unset single param
68
+ *
69
+ * @param string name
70
+ * @return void
71
+ **/
72
+ public function unsetParam($name)
73
+ {
74
+ unset($this->params[$name]);
75
+ }
76
+
77
+ /**
78
+ * set single param with multiple values
79
+ *
80
+ * @param string name
81
+ * @param array of strings values
82
+ * @return void
83
+ **/
84
+ public function setArrayParam($name, $values)
85
+ {
86
+ $this->params[$name] = $values;
87
+ }
88
+
89
+ /**
90
+ * @param FACTFinder_Abstract_IConfiguration config
91
+ **/
92
+ public function setConfig(FACTFinder_Abstract_Configuration $config)
93
+ {
94
+ $this->config = $config;
95
+ }
96
+
97
+ /**
98
+ * @return array
99
+ **/
100
+ public function getParams()
101
+ {
102
+ return $this->params;
103
+ }
104
+
105
+ /**
106
+ * @return FACTFinder_Abstract_IConfiguration
107
+ **/
108
+ protected function getConfig()
109
+ {
110
+ return $this->config;
111
+ }
112
+ }
lib/FACTFinder/Abstract/ProductCampaignAdapter.php ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * adapter for the factfinder product campaign data
5
+ *
6
+ * @author Rudolf Batt <rb@omikron.net>, Martin Buettner <martin.buettner@omikron.net>
7
+ * @version $Id: ProductCampaignAdapter.php 43440 2012-02-08 12:42:13Z martin.buettner $
8
+ * @package FACTFinder\Abstract
9
+ */
10
+ abstract class FACTFinder_Abstract_ProductCampaignAdapter extends FACTFinder_Abstract_Adapter
11
+ {
12
+ protected $productIds = array();
13
+ protected $isShoppingCartCampaign = false;
14
+ protected $campaignsUpToDate = false;
15
+
16
+ protected $campaigns;
17
+
18
+ /**
19
+ * @throws Exception if there is no query or no catalog-parameter set at the dataprovider
20
+ */
21
+ protected function getData()
22
+ {
23
+ $params = $this->getDataProvider()->getParams();
24
+ if (empty($params['productNumber'])) {
25
+ $this->log->error("No product number was set.");
26
+ throw new Exception("No product number was set.");
27
+ }
28
+ return $this->getDataProvider()->getData();
29
+ }
30
+
31
+ /**
32
+ * Set ids of products to be compared
33
+ *
34
+ * @param array $productIds list of integers
35
+ **/
36
+ public function setProductIds($productIds) {
37
+ $this->productIds = $productIds;
38
+ $this->campaignsUpToDate = false;
39
+ if($this->isShoppingCartCampaign) {
40
+ $this->getDataProvider()->setArrayParam('productNumber',$this->productIds);
41
+ } else {
42
+ $this->getDataProvider()->setParam('productNumber', $this->productIds[0]);
43
+ }
44
+ }
45
+
46
+ /**
47
+ * Adds an id to the list of products to be compared
48
+ *
49
+ * @param int $productId
50
+ **/
51
+ public function addProductId($productId) {
52
+ $this->productIds[] = $productId;
53
+ $this->campaignsUpToDate = false;
54
+ if($this->isShoppingCartCampaign) {
55
+ $this->getDataProvider()->setArrayParam('productNumber',$this->productIds);
56
+ } else {
57
+ $this->getDataProvider()->setParam('productNumber', $this->productIds[0]);
58
+ }
59
+ }
60
+
61
+ /**
62
+ * Sets the adapter up for fetching campaigns on product detail pages
63
+ **/
64
+ public function makeProductCampaign() {
65
+ $this->isShoppingCartCampaign = false;
66
+ $this->campaignsUpToDate = false;
67
+ $this->getDataProvider()->setParam('do', 'getProductCampaigns');
68
+ $this->getDataProvider()->setParam('productNumber', $this->productIds[0]);
69
+ }
70
+
71
+ /**
72
+ * Sets the adapter up for fetching campaigns on shopping cart pages
73
+ **/
74
+ public function makeShoppingCartCampaign() {
75
+ $this->isShoppingCartCampaign = true;
76
+ $this->campaignsUpToDate = false;
77
+ $this->getDataProvider()->setParam('do', 'getShoppingCartCampaigns');
78
+ $this->getDataProvider()->setArrayParam('productNumber',$this->productIds);
79
+ }
80
+
81
+ /**
82
+ * returns the campaigns
83
+ *
84
+ * @return FACTFinder_CampaignIterator
85
+ */
86
+ public function getCampaigns() {
87
+ if (!$this->campaigns || $this->campaigns == null) {
88
+ $this->campaigns = $this->createCampaigns();
89
+ $this->campaignsUpToDate == true;
90
+ }
91
+ return $this->campaigns;
92
+ }
93
+
94
+ /**
95
+ * create campaigns
96
+ *
97
+ * @return FACTFinder_CampaignIterator
98
+ */
99
+ abstract protected function createCampaigns();
100
+ }
lib/FACTFinder/Abstract/RecommendationAdapter.php ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * adapter for the factfinder recommendation engine
5
+ *
6
+ * @author Rudolf Batt <rb@omikron.net>
7
+ * @version $Id$
8
+ * @package FACTFinder\Abstract
9
+ */
10
+ abstract class FACTFinder_Abstract_RecommendationAdapter extends FACTFinder_Abstract_Adapter
11
+ {
12
+ protected $productIds = array();
13
+ protected $recommendation;
14
+ protected $recommendationUpToDate = false;
15
+
16
+ protected $idsOnly = false;
17
+ /*
18
+ * Option for XML query. 0 means "no maximum".
19
+ */
20
+ protected $maxResults = 0;
21
+
22
+ /*
23
+ * @return int $maxResults
24
+ */
25
+ public function getMaxResults() {
26
+ return $this->maxResults;
27
+ }
28
+
29
+ /*
30
+ * @param int $count positive integer (negative will be treated as 0)
31
+ */
32
+ public function setMaxResults($count) {
33
+ $this->maxResults = $count < 1 ? 0 : $count;
34
+ if($count > 0) $this->getDataProvider()->setParam('maxResults', $count);
35
+ else $this->getDataProvder()->unsetParam('maxResults');
36
+ }
37
+
38
+ /**
39
+ * Set id of product to base recommendation on
40
+ *
41
+ * @param int $productId
42
+ **/
43
+ public function setProductId($productId) {
44
+ $this->productIds = array($productId);
45
+ $this->getDataProvider()->setParam('id', $productId);
46
+ $this->recommendationUpToDate = false;
47
+ }
48
+
49
+ public function setIdsOnly($idsOnly) {
50
+ // Reset the recommendations, if more detail is wanted than before
51
+ if($this->idsOnly && !$idsOnly) $recommendationUpToDate = false;
52
+ $this->idsOnly = $idsOnly;
53
+ $this->getDataProvider()->setParam('idsOnly', $idsOnly ? 'true' : 'false');
54
+ }
55
+
56
+ /**
57
+ * creates the recommendation-records
58
+ *
59
+ * @param string id
60
+ * @return array of FACTFinder_Record objects
61
+ **/
62
+ abstract protected function createRecommendations();
63
+
64
+ /**
65
+ * returns recommendations for specified id. if no id is set, try to fetch parameter 'id'.
66
+ * if no id is available, there will be a warning raised and returning an empty array
67
+ *
68
+ * @return FACTFinder_Result
69
+ **/
70
+ public function getRecommendations() {
71
+ if (empty($this->productIds)) {
72
+ $requestParams = $this->getParamsParser()->getRequestParams();
73
+ if (isset($requestParams['id'])) {
74
+ $this->productIds = array($requestParams['id']);
75
+ }
76
+ if (empty($this->productIds)) {
77
+ trigger_error('recommendations can not be loaded without id. could not load id from request', E_USER_WARNING);
78
+ return array();
79
+ }
80
+ }
81
+ if (!$this->recommendationUpToDate || !isset($this->recommendation) || $this->recommendation == null) {
82
+ $this->recommendation = $this->createRecommendations();
83
+ $this->recommendationUpToDate = true;
84
+ }
85
+ return $this->recommendation;
86
+ }
87
+ }
lib/FACTFinder/Abstract/ScicAdapter.php ADDED
@@ -0,0 +1,152 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * abstract adapter for the shopping cart information collector tracking
5
+ *
6
+ * @author Rudolf Batt <rb@omikron.net>
7
+ * @version $Id: ScicAdapter.php 25896 2010-06-29 08:34:06Z rb $
8
+ * @package FACTFinder\Abstract
9
+ */
10
+ abstract class FACTFinder_Abstract_ScicAdapter extends FACTFinder_Abstract_Adapter
11
+ {
12
+ /**
13
+ * let the data provider save the tracking params
14
+ *
15
+ * @return boolean $success
16
+ */
17
+ abstract protected function applyTracking();
18
+
19
+ /**
20
+ * if all needed parameters are available at the request like described in the documentation, just use this method to
21
+ * fetch the needed parameters and track them
22
+ * insure to set a session id if there is no parameter "sid". if this argument is not set or empty and the parameter
23
+ * "sid" is not available, it will try to use session_id() to fetch one.
24
+ *
25
+ * @param string $sid session id
26
+ * @return boolean $success
27
+ */
28
+ public function doTrackingFromRequest($sid = null)
29
+ {
30
+ $params = $this->getParamsParser()->getServerRequestParams();
31
+ if (!empty($sid)) {
32
+ $params['sid'] = $sid;
33
+ } else if (empty($params['sid'])) {
34
+ $params['sid'] = session_id();
35
+ }
36
+ $this->getDataProvider()->setParams($params);
37
+ return $this->applyTracking();
38
+ }
39
+
40
+ /**
41
+ * track a detail click on a product
42
+ *
43
+ * @param string $id id of product
44
+ * @param string $sid session id (if empty, then try to set using the function session_id() )
45
+ * @param string $query query which led to the product
46
+ * @param int $pos position of product in the search result
47
+ * @param int $origPos original position of product in the search result. this data is delivered by FACT-Finder (optional - is set equals to $position by default)
48
+ * @param int $page page number where the product was clicked (optional - is 1 by default)
49
+ * @param double $simi similiarity of the product (optional - is 100.00 by default)
50
+ * @param string $title title of product (optional - is empty by default)
51
+ * @param int $pageSize size of the page where the product was found (optional - is 12 by default)
52
+ * @param int $origPageSize original size of the page before the user could have changed it (optional - is set equals to $page by default)
53
+ * @return boolean $success
54
+ */
55
+ public function trackClick($id, $sid = null, $query, $pos, $origPos = -1, $page = 1, $simi = 100.0, $title = '',
56
+ $pageSize = 12, $origPageSize = -1)
57
+ {
58
+ if (empty($sid)) $sid = session_id();
59
+ if ($origPos == -1) $origPos = $pos;
60
+ if ($origPageSize == -1) $origPageSize = $pageSize;
61
+
62
+ $this->getDataProvider()->setParams(
63
+ array(
64
+ 'query' => $query,
65
+ 'id' => $id,
66
+ 'pos' => $pos,
67
+ 'origPos' => $origPos,
68
+ 'page' => $page,
69
+ 'simi' => $simi,
70
+ 'sid' => $sid,
71
+ 'title' => $title,
72
+ 'event' => 'click',
73
+ 'pageSize' => $pageSize,
74
+ 'origPageSize' => $origPageSize
75
+ )
76
+ );
77
+ return $this->applyTracking();
78
+ }
79
+
80
+ /**
81
+ * track a product which was added to the cart
82
+ *
83
+ * @param string $id id of product
84
+ * @param string $sid session id (if empty, then try to set using the function session_id() )
85
+ * @param int $count number of items purchased for each product (optional - default 1)
86
+ * @param double $price this is the single unit price (optional)
87
+ * @return boolean $success
88
+ */
89
+ public function trackCart($id, $sid = null, $count = 1, $price = null, $userid = null)
90
+ {
91
+ if (empty($sid)) $sid = session_id();
92
+ $params = array(
93
+ 'id' => $id,
94
+ 'sid' => $sid,
95
+ 'count' => $count,
96
+ 'event' => 'cart'
97
+ );
98
+
99
+ if (!empty($price)) $params['price'] = $price;
100
+ if (!empty($userid)) $params['userid'] = $userid;
101
+
102
+ $this->getDataProvider()->setParams($params);
103
+ return $this->applyTracking();
104
+ }
105
+
106
+ /**
107
+ * track a product which was purchased
108
+ *
109
+ * @param string $id id of product
110
+ * @param string $sid session id (if empty, then try to set using the function session_id() )
111
+ * @param int $count number of items purchased for each product (optional - default 1)
112
+ * @param double $price this is the single unit price (optional)
113
+ * @return boolean $success
114
+ */
115
+ public function trackCheckout($id, $sid = null, $count = 1, $price = null, $userid = null)
116
+ {
117
+ if (empty($sid)) $sid = session_id();
118
+ $params = array(
119
+ 'id' => $id,
120
+ 'sid' => $sid,
121
+ 'count' => $count,
122
+ 'event' => 'checkout'
123
+ );
124
+
125
+ if (!empty($price)) $params['price'] = $price;
126
+ if (!empty($userid)) $params['userid'] = $userid;
127
+
128
+ $this->getDataProvider()->setParams($params);
129
+ return $this->applyTracking();
130
+ }
131
+
132
+ /**
133
+ * track a click on a recommended product
134
+ *
135
+ * @param string $id id of product
136
+ * @param string $sid session id (if empty, then try to set using the function session_id() )
137
+ * @param int $mainId ID of the product for which the clicked-upon item was recommended
138
+ * @return boolean $success
139
+ */
140
+ public function trackRecommendationClick($id, $sid = null, $mainId)
141
+ {
142
+ if (empty($sid)) $sid = session_id();
143
+ $params = array(
144
+ 'id' => $id,
145
+ 'sid' => $sid,
146
+ 'mainId' => $mainId,
147
+ 'event' => 'recommendationClick'
148
+ );
149
+ $this->getDataProvider()->setParams($params);
150
+ return $this->applyTracking();
151
+ }
152
+ }
lib/FACTFinder/Abstract/SearchAdapter.php ADDED
@@ -0,0 +1,252 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * adapter for the factfinder search
5
+ *
6
+ * @author Rudolf Batt <rb@omikron.net>
7
+ * @version $Id: SearchAdapter.php 25935 2010-06-29 15:04:45Z rb $
8
+ * @package FACTFinder\Abstract
9
+ */
10
+ abstract class FACTFinder_Abstract_SearchAdapter extends FACTFinder_Abstract_Adapter
11
+ {
12
+ private $searchParams;
13
+ private $result;
14
+ private $asn;
15
+ private $sorting;
16
+ private $paging;
17
+ private $productsPerPageOptions;
18
+ private $breadCrumbTrail;
19
+ private $campaigns;
20
+ private $singleWordSearch;
21
+
22
+ const NO_QUERY = 'noQuery';
23
+ const NO_RESULT = 'noResult';
24
+ const RESULTS_FOUND = 'resultsFound';
25
+ const NOTHING_FOUND = 'nothingFound';
26
+
27
+ /**
28
+ * @throws Exception if there is no query or no catalog-parameter set at the dataprovider
29
+ */
30
+ protected function getData()
31
+ {
32
+ $params = $this->getDataProvider()->getParams();
33
+ if (empty($params['query']) && empty($params['seoPath'])
34
+ && (empty($params['catalog']) || $params['catalog'] != 'true')) {
35
+ $this->log->error("No query was set.");
36
+ throw new Exception(self::NO_QUERY);
37
+ }
38
+ return $this->getDataProvider()->getData();
39
+ }
40
+
41
+ /**
42
+ * returns the search status of the article number search, which is one of this class constants:
43
+ * NO_RESULT it was not an article number search
44
+ * NOTHING_FOUND is article number search, but nothing found
45
+ * RESULTS_FOUND found article by article number
46
+ * returns null, if no article number search was done
47
+ *
48
+ * @return string status
49
+ **/
50
+ abstract public function getArticleNumberSearchStatus();
51
+
52
+ /**
53
+ * returns true if the query matches the article number search regex, else false. also returns false, when there
54
+ * was any error
55
+ *
56
+ * @return boolean isArticleNumberSearch
57
+ **/
58
+ abstract public function isArticleNumberSearch();
59
+
60
+ /**
61
+ * returns true when search timed out. even if true, nevertheless result records may exist
62
+ *
63
+ * @return boolean
64
+ **/
65
+ abstract public function isSearchTimedOut();
66
+
67
+ /**
68
+ * returns the search status of the search, which is one of this class constants:
69
+ * NO_RESULT: there seems to be any error. no search done
70
+ * NOTHING_FOUND: search done, but nothing found; maybe campaigns are available
71
+ * RESULTS_FOUND: results found
72
+ * returns null, if no article number search was done
73
+ *
74
+ * @return string status
75
+ **/
76
+ abstract public function getStatus();
77
+
78
+ /**
79
+ * creates the result object
80
+ *
81
+ * @return FACTFinder_Result
82
+ **/
83
+ abstract protected function createResult();
84
+
85
+ /**
86
+ * creates the asn object
87
+ *
88
+ * @return FACTFinder_Asn
89
+ **/
90
+ abstract protected function createAsn();
91
+
92
+ /**
93
+ * creates the sorting object
94
+ *
95
+ * @return array of FACTFinder_Item objects
96
+ **/
97
+ abstract protected function createSorting();
98
+
99
+ /**
100
+ * creates the paging object
101
+ *
102
+ * @return FACTFinder_Paging object
103
+ **/
104
+ abstract protected function createPaging();
105
+
106
+ /**
107
+ * creates the paging object
108
+ *
109
+ * @return FACTFinder_ProductsPerPageOptions object
110
+ **/
111
+ abstract protected function createProductsPerPageOptions();
112
+
113
+ /**
114
+ * create breadcrumbtrail
115
+ *
116
+ * @return array of FACTFinder_BreadCrumbItem objects
117
+ */
118
+ abstract protected function createBreadCrumbTrail();
119
+
120
+ /**
121
+ * create campaigns
122
+ *
123
+ * @return FACTFinder_CampaignIterator
124
+ */
125
+ abstract protected function createCampaigns();
126
+
127
+ /**
128
+ * create sindle word search
129
+ *
130
+ * @return array of FACTFinder_SuggestQuery objects
131
+ */
132
+ abstract protected function createSingleWordSearch();
133
+
134
+ /**
135
+ * returns the search params object
136
+ *
137
+ * @return FACTFinder_Parameters result
138
+ **/
139
+ abstract protected function createSearchParams();
140
+
141
+ /**
142
+ * returns the search params object
143
+ *
144
+ * @return FACTFinder_Parameters result
145
+ **/
146
+ public function getSearchParams() {
147
+ if ($this->searchParams == null) {
148
+ $this->searchParams = $this->createSearchParams();
149
+ }
150
+ return $this->searchParams;
151
+ }
152
+
153
+ /**
154
+ * returns the result object
155
+ *
156
+ * @return FACTFinder_Result result
157
+ **/
158
+ public function getResult() {
159
+ if ($this->result == null) {
160
+ $this->result = $this->createResult();
161
+ }
162
+ return $this->result;
163
+ }
164
+
165
+ /**
166
+ * returns the asn object
167
+ *
168
+ * @return FACTFinder_Asn
169
+ **/
170
+ public function getAsn() {
171
+ if ($this->asn == null) {
172
+ $this->asn = $this->createAsn();
173
+ }
174
+ return $this->asn;
175
+ }
176
+
177
+ /**
178
+ * returns the sorting
179
+ *
180
+ * @return array of FACTFinder_SortItem objects
181
+ **/
182
+ public function getSorting() {
183
+ if ($this->sorting == null) {
184
+ $this->sorting = $this->createSorting();
185
+ }
186
+ return $this->sorting;
187
+ }
188
+
189
+ /**
190
+ * returns the paging
191
+ *
192
+ * @return FACTFinder_Paging object
193
+ **/
194
+ public function getPaging() {
195
+ if ($this->paging == null) {
196
+ $this->paging = $this->createPaging();
197
+ }
198
+ return $this->paging;
199
+ }
200
+
201
+ /**
202
+ * return products-per-page-options
203
+ *
204
+ * @return FACTFinder_ProductsPerPageOptions object
205
+ */
206
+ public function getProductsPerPageOptions() {
207
+ if ($this->productsPerPageOptions == null) {
208
+ $this->productsPerPageOptions = $this->createProductsPerPageOptions();
209
+ }
210
+ return $this->productsPerPageOptions;
211
+ }
212
+
213
+ /**
214
+ * returns the breadcrumbtrail
215
+ *
216
+ * @return array of FACTFinder_BreadCrumbItem objects
217
+ */
218
+ public function getBreadCrumbTrail() {
219
+ if ($this->breadCrumbTrail == null) {
220
+ $this->breadCrumbTrail = $this->createBreadCrumbTrail();
221
+ }
222
+ return $this->breadCrumbTrail;
223
+ }
224
+
225
+ /**
226
+ * returns the campaigns
227
+ *
228
+ * @return FACTFinder_CampaignIterator
229
+ */
230
+ public function getCampaigns() {
231
+ if ($this->campaigns == null) {
232
+ $this->campaigns = $this->createCampaigns();
233
+ }
234
+ return $this->campaigns;
235
+ }
236
+
237
+ /**
238
+ * if the result was not good and there are more than one queries used for it, this method will return an array of
239
+ * FACTFinder_SuggestQuery objects, for each word a single item. by clicking at a singleWordSearch item, the result
240
+ * will get better
241
+ * please notice, that this feature has to be actived in the FACT-Finder search environment, so this method returns
242
+ * an empty array, if there are no singleWordSearch items
243
+ *
244
+ * @return array of FACTFinder_SuggestQuery objects
245
+ */
246
+ public function getSingleWordSearch() {
247
+ if ($this->singleWordSearch == null) {
248
+ $this->singleWordSearch = $this->createSingleWordSearch();
249
+ }
250
+ return $this->singleWordSearch;
251
+ }
252
+ }
lib/FACTFinder/Abstract/SimilarRecordsAdapter.php ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * adapter for the factfinder "similar records" data
5
+ *
6
+ * @author Martin Buettner <martin.buettner@omikron.net>
7
+ * @version $Id: SimilarRecordsAdapter.php 42804 2012-01-20 10:46:43Z mb $
8
+ * @package FACTFinder\Abstract
9
+ */
10
+ abstract class FACTFinder_Abstract_SimilarRecordsAdapter extends FACTFinder_Abstract_Adapter
11
+ {
12
+ protected $productId;
13
+ private $similarAttributes;
14
+ private $similarRecords;
15
+ protected $attributesUpToDate = false;
16
+ protected $recordsUpToDate = false;
17
+
18
+ protected $idsOnly = false;
19
+
20
+ /*
21
+ * Option for XML query. 0 means "no maximum".
22
+ */
23
+ private $maxRecordCount = 0;
24
+
25
+ /**
26
+ * Set id of product to get similar records for
27
+ *
28
+ * @param int $productId
29
+ **/
30
+ public function setProductId($productId) {
31
+ $this->productId = $productId;
32
+ $this->getDataProvider()->setParam('id', $productId);
33
+ $this->attributesUpToDate = false;
34
+ $this->recordsUpToDate = false;
35
+ }
36
+
37
+ /*
38
+ * @return int $maxRecordCount
39
+ */
40
+ public function getMaxRecordCount() {
41
+ return $this->maxRecordCount;
42
+ }
43
+
44
+ /*
45
+ * @param int $count positive integer (negative will be treated as 0)
46
+ */
47
+ public function setMaxRecordCount($count) {
48
+ $this->maxRecordCount = $count < 1 ? 0 : $count;
49
+ if($count > 0) $this->getDataProvider()->setParam('maxRecordCount', $count);
50
+ else $this->getDataProvder()->unsetParam('maxRecordCount');
51
+ }
52
+
53
+ public function setIdsOnly($idsOnly) {
54
+ // Reset the similar records, if more detail is wanted than before
55
+ if($this->idsOnly && !$idsOnly) $this->recordsUpToDate = false;
56
+ $this->idsOnly = $idsOnly;
57
+ if($idsOnly)
58
+ $this->getDataProvider()->setParam('idsOnly','true');
59
+ else
60
+ $this->getDataProvider()->unsetParam('idsOnly');
61
+ }
62
+
63
+ /**
64
+ * returns similar attributes for previously specified id. if no id is set, try to fetch parameter 'id'.
65
+ * if no id is available, there will be a warning raised and returning an empty array
66
+
67
+ * @return array $similarAttributes of strings (field names as keys)
68
+ */
69
+ public function getSimilarAttributes() {
70
+ if (empty($this->productId)) {
71
+ $requestParams = $this->getParamsParser()->getRequestParams();
72
+ if (isset($requestParams['id'])) {
73
+ $this->productId = $requestParams['id'];
74
+ }
75
+ if (empty($this->productId)) {
76
+ trigger_error('recommendations can not be loaded without id. could not load id from request', E_USER_WARNING);
77
+ return array();
78
+ }
79
+ }
80
+ if (!$this->attributesUpToDate || !isset($this->similarAttributes) || $this->similarAttributes == null) {
81
+ $this->similarAttributes = $this->createSimilarAttributes();
82
+ $this->attributesUpToDate = true;
83
+ }
84
+ return $this->similarAttributes;
85
+ }
86
+
87
+ /**
88
+ * returns similar records for specified id. if no id is set, try to fetch parameter 'id'.
89
+ * if no id is available, there will be a warning raised and returning an empty array.
90
+ *
91
+ * @param string $id (optional; if not set try to fetch from request param)
92
+ * @return array $similarRecords list of FACTFinder_Record objects
93
+ */
94
+ public function getSimilarRecords() {
95
+ if (empty($this->productId)) {
96
+ $requestParams = $this->getParamsParser()->getRequestParams();
97
+ if (isset($requestParams['id'])) {
98
+ $this->productId = $requestParams['id'];
99
+ }
100
+ if (empty($this->productId)) {
101
+ trigger_error('similar records can not be loaded without id. could not load id from request', E_USER_WARNING);
102
+ return array();
103
+ }
104
+ }
105
+ if (!$this->recordsUpToDate || !isset($this->similarRecords) || $this->similarRecords == null) {
106
+ $this->similarRecords = $this->createSimilarRecords();
107
+ $this->recordsUpToDate = true;
108
+ }
109
+ return $this->similarRecords;
110
+ }
111
+
112
+ /**
113
+ * @return array $similarAttributes of strings (field names as keys)
114
+ */
115
+ abstract protected function createSimilarAttributes();
116
+
117
+ /**
118
+ * @return array $similarRecords list of FACTFinder_Record objects
119
+ */
120
+ abstract protected function createSimilarRecords();
121
+ }
lib/FACTFinder/Abstract/SuggestAdapter.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * adapter for factfinder's suggest
5
+ *
6
+ * @author Rudolf Batt <rb@omikron.net>
7
+ * @version $Id: SuggestAdapter.php 25893 2010-06-29 08:19:43Z rb $
8
+ * @package FACTFinder\Abstract
9
+ */
10
+ abstract class FACTFinder_Abstract_SuggestAdapter extends FACTFinder_Abstract_Adapter
11
+ {
12
+ private $suggestions;
13
+
14
+ /**
15
+ * get suggestions created by createSuggesions()
16
+ *
17
+ * @return mixed
18
+ */
19
+ public function getSuggestions()
20
+ {
21
+ if ($this->suggestions == null) {
22
+ $this->suggestions = $this->createSuggestions();
23
+ }
24
+ return $this->suggestions;
25
+ }
26
+
27
+ /**
28
+ * create and return suggestions. dependend to the implementation this can be any type
29
+ *
30
+ * @return mixed
31
+ */
32
+ abstract protected function createSuggestions();
33
+ }
lib/FACTFinder/Abstract/TagCloudAdapter.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * adapter for the factfinder tagcloud data
5
+ *
6
+ * @author Rudolf Batt <rb@omikron.net>
7
+ * @version $Id: TagCloudAdapter.php 25893 2010-06-29 08:19:43Z rb $
8
+ * @package FACTFinder\Abstract
9
+ */
10
+ abstract class FACTFinder_Abstract_TagCloudAdapter extends FACTFinder_Abstract_Adapter
11
+ {
12
+ private $tagCloud;
13
+
14
+ /**
15
+ * get tag cloud
16
+ *
17
+ * @return array $tagCloud list of FACTFinder_Tag objects
18
+ */
19
+ public function getTagCloud() {
20
+ if ($this->tagCloud == null) {
21
+ $this->tagCloud = $this->createTagCloud();
22
+ }
23
+ return $this->tagCloud;
24
+ }
25
+
26
+ /**
27
+ * @return array $tagCloud list of FACTFinder_Tag objects
28
+ */
29
+ abstract protected function createTagCloud();
30
+ }
lib/FACTFinder/AdvisorAnswer.php ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * represents an answer to a question of an advisor campaign (see FACTFinder_AdvisorQuestion)
4
+ * relevant for FF versions >= 6.7
5
+ *
6
+ * @author Martin Buettner <martin.buettner@omikron.net>
7
+ * @version $Id: AdvisorAnswer.php 41893 2012-01-16 13:47:52Z mb $
8
+ * @package FACTFinder\Common
9
+ */
10
+ class FACTFinder_AdvisorAnswer
11
+ {
12
+ private $text;
13
+ private $params;
14
+
15
+ private $subquestions = array();
16
+
17
+ /**
18
+ * @param string text
19
+ * @param string params
20
+ * @param array subquestions; array of FACTFinder_AdvisorQuestion objects
21
+ */
22
+ public function __construct($text = '', $params = '', $subquestions = array()) {
23
+ $this->text = trim($text);
24
+ $this->params = trim($params);
25
+ $this->addSubquestions($subquestions);
26
+ }
27
+
28
+ /**
29
+ * @return string text
30
+ */
31
+ public function getText() {
32
+ return $this->text;
33
+ }
34
+
35
+ /**
36
+ * @return string params
37
+ */
38
+ public function getParams() {
39
+ return $this->params;
40
+ }
41
+
42
+ /**
43
+ * add follow-up questions to this answer
44
+ *
45
+ * @param array of FACTFinder_AdvisorQuestion objects
46
+ * @return void
47
+ */
48
+ public function addSubquestions(array $subquestions) {
49
+ foreach ($subquestions AS $question) {
50
+ $this->subquestions[] = $question;
51
+ }
52
+ }
53
+
54
+ /**
55
+ * true if follow-up questions exist
56
+ *
57
+ * @return boolean
58
+ */
59
+ public function hasSubquestions() {
60
+ return sizeof($this->subquestions) > 0;
61
+ }
62
+
63
+ /**
64
+ * @return array of FACTFinder_AdvisorQuestion objects
65
+ */
66
+ public function getSubquestions() {
67
+ return $this->subquestions;
68
+ }
69
+ }
lib/FACTFinder/AdvisorQuestion.php ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * represents a question of an advisor campaign
4
+ * relevant for FF versions >= 6.7
5
+ *
6
+ * @author Martin Buettner <martin.buettner@omikron.net>
7
+ * @version $Id: AdvisorQuestion.php 41893 2012-01-16 13:47:52Z mb $
8
+ * @package FACTFinder\Common
9
+ */
10
+ class FACTFinder_AdvisorQuestion
11
+ {
12
+ private $text;
13
+
14
+ private $answers = array();
15
+
16
+ /**
17
+ * @param string question text
18
+ * @param array answers; array of FACTFinder_AdvisorAnswer objects
19
+ */
20
+ public function __construct($text = '', $answers = array()) {
21
+ $this->text = trim($text);
22
+ $this->addAnswers($answers);
23
+ }
24
+
25
+ /**
26
+ * @return string text
27
+ */
28
+ public function getText() {
29
+ return $this->text;
30
+ }
31
+
32
+ /**
33
+ * add answers to this question
34
+ *
35
+ * @param array of FACTFinder_AdvisorAnswer objects
36
+ * @return void
37
+ */
38
+ public function addAnswers(array $answers) {
39
+ foreach ($answers AS $answer) {
40
+ $this->answers[] = $answer;
41
+ }
42
+ }
43
+
44
+ /**
45
+ * true if answers exist
46
+ *
47
+ * @return boolean
48
+ */
49
+ public function hasAnswers() {
50
+ return sizeof($this->answers) > 0;
51
+ }
52
+
53
+ /**
54
+ * @return array of FACTFinder_AdvisorAnswer objects
55
+ */
56
+ public function getAnswers() {
57
+ return $this->answers;
58
+ }
59
+ }
lib/FACTFinder/Asn.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * represents a group in the ASN which contains several filters. By iterating over an ASN object, you will
5
+ * get FACTFinder_AsnGroup objects in the loop.
6
+ *
7
+ * @author Rudolf Batt <rb@omikron.net>
8
+ * @version $Id: Asn.php 25893 2010-06-29 08:19:43Z rb $
9
+ * @package FACTFinder\Common
10
+ */
11
+ class FACTFinder_Asn extends ArrayIterator
12
+ {
13
+ /**
14
+ * decorates the FACTFinder_AsnGroup::hasPreviewImages() method for each group in the asn. so if one group has
15
+ * preview images, this method returns true
16
+ *
17
+ * @return boolean
18
+ */
19
+ public function hasPreviewImages()
20
+ {
21
+ $hasPreviewImages = false;
22
+ foreach ($this AS $group) {
23
+ if ($group->hasPreviewImages()) {
24
+ $hasPreviewImages = true;
25
+ break;
26
+ }
27
+ }
28
+ return $hasPreviewImages;
29
+ }
30
+ }
lib/FACTFinder/AsnFilterItem.php ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * represents an filterable item from the after search navigation
5
+ *
6
+ * @author Rudolf Batt <rb@omikron.net>
7
+ * @version $Id: AsnFilterItem.php 25893 2010-06-29 08:19:43Z rb $
8
+ * @package FACTFinder\Common
9
+ */
10
+ class FACTFinder_AsnFilterItem extends FACTFinder_Item
11
+ {
12
+ private $matchCount;
13
+ private $clusterLevel;
14
+ private $previewImage = null;
15
+ private $field;
16
+
17
+ public function __construct($value, $url, $isSelected = false, $matchCount = 0, $clusterLevel = 0, $previewImage = null, $field = ''){
18
+ parent::__construct($value, $url, $isSelected);
19
+ $this->matchCount = intval($matchCount);
20
+ $this->clusterLevel = intval($clusterLevel);
21
+ $this->previewImage = strval($previewImage);
22
+ $this->field = strval($field);
23
+ }
24
+
25
+ public function getType() {
26
+ return 'item';
27
+ }
28
+
29
+ /**
30
+ * @return String
31
+ */
32
+ public function getField() {
33
+ return $this->field;
34
+ }
35
+
36
+ /**
37
+ * @return int
38
+ */
39
+ public function getMatchCount() {
40
+ return $this->matchCount;
41
+ }
42
+
43
+ /**
44
+ * @return int
45
+ */
46
+ public function getClusterLevel() {
47
+ return $this->clusterLevel;
48
+ }
49
+
50
+ /**
51
+ * return url of a preview image or null if there is no set
52
+ *
53
+ * @return string image url or null if none exists
54
+ */
55
+ public function getPreviewImage() {
56
+ return $this->previewImage;
57
+ }
58
+
59
+ /**
60
+ * @return boolean
61
+ */
62
+ public function hasPreviewImage() {
63
+ return !empty($this->previewImage);
64
+ }
65
+ }
lib/FACTFinder/AsnGroup.php ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * represents a group in the ASN which contains several filters. By iterating over an AsnGroup object, you will
5
+ * get AsnFilterItem objects in the loop.
6
+ *
7
+ * @author Rudolf Batt <rb@omikron.net>
8
+ * @version $Id: AsnGroup.php 25893 2010-06-29 08:19:43Z rb $
9
+ * @category Collection
10
+ * @package FACTFinder\Common
11
+ */
12
+ class FACTFinder_AsnGroup extends ArrayIterator
13
+ {
14
+ private $name;
15
+ private $detailedLinkCount;
16
+ private $unit;
17
+ private $hasPreviewImages = false;
18
+ private $hasSelectedItems = false;
19
+ private $isSliderStyle = false;
20
+
21
+ /**
22
+ * constructor
23
+ *
24
+ * @param array asn filters to add to this group (default: empty array)
25
+ * @param string name of the group (default: empty string)
26
+ * @param int number of detail links to show (default: 0)
27
+ * @param string untit character of the group (default: empty string)
28
+ * @param string style; possible values: DEFAULT|SLIDER|COLOR (default: DEFAULT)
29
+ */
30
+ public function __construct(array $asnFilters = array(), $name = '', $detailedLinkCount = 0, $unit = '', $style = 'DEFAULT') {
31
+ $this->name = strval($name);
32
+ $this->detailedLinkCount = intval($detailedLinkCount);
33
+ $this->unit = strval($unit);
34
+ $this->style = $style;
35
+
36
+ parent::__construct();
37
+ $this->addFilters($asnFilters);
38
+ }
39
+
40
+ /**
41
+ * return true if group filtering should be done in slider style
42
+ *
43
+ * @return boolean
44
+ */
45
+ public function isSliderStyle() {
46
+ return $this->style == 'SLIDER';
47
+ }
48
+
49
+ /**
50
+ * @return boolean
51
+ */
52
+ public function isColorStyle() {
53
+ return $this->style == 'COLOR';
54
+ }
55
+
56
+ /**
57
+ * @return boolean
58
+ */
59
+ public function isDefaultStyle() {
60
+ return !$this->isSliderStyle() && !$this->isColorStyle();
61
+ }
62
+
63
+ /**
64
+ * return boolean true if one or more items has a preview image
65
+ */
66
+ public function hasPreviewImages()
67
+ {
68
+ return $this->hasPreviewImages;
69
+ }
70
+
71
+ /**
72
+ * return boolean true if one or more items are selected
73
+ */
74
+ public function hasSelectedItems()
75
+ {
76
+ return $this->hasSelectedItems;
77
+ }
78
+
79
+ /**
80
+ * add every filter from the given array to this group
81
+ *
82
+ * @param array of filter objects
83
+ * @return void
84
+ */
85
+ public function addFilters(array $filters)
86
+ {
87
+ foreach($filters AS $filter) {
88
+ $this->addFilter($filter);
89
+ }
90
+ }
91
+
92
+ /**
93
+ * @param filter object
94
+ * @return void
95
+ */
96
+ public function addFilter($filter)
97
+ {
98
+ if ($filter instanceof FACTFinder_AsnFilterItem) {
99
+ if ($filter->hasPreviewImage()) {
100
+ $this->hasPreviewImages = true;
101
+ } else if ($filter->isSelected()) {
102
+ $this->hasSelectedItems = true;
103
+ }
104
+ }
105
+ parent::append($filter);
106
+ }
107
+
108
+ /**
109
+ * @return string name
110
+ */
111
+ public function getName() {
112
+ return $this->name;
113
+ }
114
+
115
+ /**
116
+ * @return string unit
117
+ */
118
+ public function getUnit() {
119
+ return $this->unit;
120
+ }
121
+
122
+ /**
123
+ * @return int
124
+ */
125
+ public function getDetailedLinkCount() {
126
+ return $this->detailedLinkCount;
127
+ }
128
+ }
lib/FACTFinder/AsnSliderFilter.php ADDED
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * represents an asn filter slider item
5
+ *
6
+ * @author Rudolf Batt <rb@omikron.net>
7
+ * @version $Id: AsnSliderFilter.php 25893 2010-06-29 08:19:43Z rb $
8
+ * @package FACTFinder\Common
9
+ */
10
+ class FACTFinder_AsnSliderFilter
11
+ {
12
+ private $absoluteMin;
13
+ private $absoluteMax;
14
+ private $selectedMin;
15
+ private $selectedMax;
16
+ private $baseUrl;
17
+ private $field;
18
+
19
+ /**
20
+ * @param string base url - it should be possible to simply append the selected min and max value
21
+ * @param float absolute min (default: 0.0)
22
+ * @param float absolute max (default: 0.0)
23
+ * @param float selected min (default: 0.0)
24
+ * @param float selected max (default: 0.0)
25
+ */
26
+ public function __construct($baseUrl, $absoluteMin = 0, $absoluteMax = 0, $selectedMin = 0, $selectedMax = 0, $field = '') {
27
+ $this->baseUrl = $baseUrl;
28
+ $this->setAbsoluteRange($absoluteMin, $absoluteMax);
29
+ $this->setSelectedRange($selectedMin, $selectedMax);
30
+ $this->field = strval($field);
31
+ }
32
+
33
+ public function getType() {
34
+ return 'slider';
35
+ }
36
+
37
+ /**
38
+ * @param float absolute min
39
+ * @param float absolute max
40
+ */
41
+ private function setAbsoluteRange($min, $max) {
42
+ $this->absoluteMin = floatval($min);
43
+ $this->absoluteMax = floatval($max);
44
+ }
45
+
46
+ /**
47
+ * @param float selected min
48
+ * @param float selected max
49
+ */
50
+ public function setSelectedRange($min, $max) {
51
+ $this->selectedMin = floatval($min);
52
+ $this->selectedMax = floatval($max);
53
+ }
54
+
55
+ /**
56
+ * return float
57
+ */
58
+ public function getAbsoluteMin() {
59
+ return $this->absoluteMin;
60
+ }
61
+
62
+ /**
63
+ * return float
64
+ */
65
+ public function getAbsoluteMax() {
66
+ return $this->absoluteMax;
67
+ }
68
+
69
+ /**
70
+ * return float
71
+ */
72
+ public function getSelectedMin() {
73
+ return $this->selectedMin;
74
+ }
75
+
76
+ /**
77
+ * return float
78
+ */
79
+ public function getSelectedMax() {
80
+ return $this->selectedMax;
81
+ }
82
+
83
+ /**
84
+ * @return string url for the current selected range
85
+ */
86
+ public function getUrl() {
87
+ return $this->baseUrl . $this->selectedMin . ' - ' . $this->selectedMax;
88
+ }
89
+
90
+ /**
91
+ * @return string base url
92
+ */
93
+ public function getBaseUrl() {
94
+ return $this->baseUrl;
95
+ }
96
+
97
+ /**
98
+ * returns true if the selected range is not the same as the absolute range
99
+ *
100
+ * @return boolean true if selected
101
+ */
102
+ public function isSelected() {
103
+ return $this->selectedMin != $this->absoluteMin || $this->selectedMax != $this->absoluteMax;
104
+ }
105
+
106
+ /**
107
+ * returns the associated field name to this filter
108
+ *
109
+ * @return string field-name
110
+ */
111
+ public function getField() {
112
+ return $this->field;
113
+ }
114
+
115
+ /**
116
+ * returns the absolute values as parameters and the select parameter-key, so the selected values must be
117
+ * appended to set the selection.
118
+ *
119
+ * @return string parameters for this filter
120
+ */
121
+ public function getValue() {
122
+ return 'filter'.$this->getField().'Absolute='.$this->getAbsoluteMin().' - '.$this->getAbsoluteMax().'&filter'.$this->getField().'=';
123
+ }
124
+ }
lib/FACTFinder/BreadCrumbItem.php ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * breadcrumb for the breadcrumb navigation
5
+ *
6
+ * @author Rudolf Batt <rb@omikron.net>
7
+ * @version $Id: BreadCrumbItem.php 25893 2010-06-29 08:19:43Z rb $
8
+ * @package FACTFinder\Common
9
+ */
10
+ class FACTFinder_BreadCrumbItem extends FACTFinder_Item
11
+ {
12
+ const SEARCH_TYPE = 'search';
13
+ const FILTER_TYPE = 'filter';
14
+
15
+ private $type;
16
+ private $fieldName;
17
+ private $fieldUnit;
18
+
19
+ /**
20
+ * @param string value
21
+ * @param string url
22
+ * @param boolean true if this breadcrumb represents the current state of the result
23
+ * @param string type should be "search" or "filter", otherwise the "is..." methods will not work (default: 'filter')
24
+ * @param string filtername
25
+ * @param string filter value
26
+ */
27
+ public function __construct($value, $url, $isSelected = false, $type = 'filter', $fieldName = '', $fieldUnit = '')
28
+ {
29
+ parent::__construct($value, $url, $isSelected);
30
+ $this->type = strval($type);
31
+ if ($this->isFilter()) {
32
+ $this->fieldName = strval($fieldName);
33
+ $this->fieldUnit = strval($fieldUnit);
34
+ }
35
+ }
36
+
37
+ /**
38
+ * @return boolean
39
+ */
40
+ public function isFilter()
41
+ {
42
+ return $this->type == self::FILTER_TYPE;
43
+ }
44
+
45
+ /**
46
+ * @return boolean
47
+ */
48
+ public function isSearch()
49
+ {
50
+ return $this->type == self::SEARCH_TYPE;
51
+ }
52
+
53
+ /**
54
+ * @return string
55
+ */
56
+ public function getFieldName()
57
+ {
58
+ return $this->fieldName;
59
+ }
60
+
61
+ /**
62
+ * @return string
63
+ */
64
+ public function getFieldUnit()
65
+ {
66
+ return $this->fieldUnit;
67
+ }
68
+ }
lib/FACTFinder/Campaign.php ADDED
@@ -0,0 +1,198 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * represents a factfinder campaign
4
+ *
5
+ * @author Rudolf Batt <rb@omikron.net>
6
+ * @version $Id: Campaign.php 25985 2010-06-30 15:31:53Z rb $
7
+ * @package FACTFinder\Common
8
+ */
9
+ class FACTFinder_Campaign
10
+ {
11
+ private $name;
12
+ private $category;
13
+
14
+ private $redirectUrl = null;
15
+ private $pushedProducts = array();
16
+ private $feedback = array();
17
+ private $activeQuestions = array();
18
+ private $advisorTree = array();
19
+
20
+ /**
21
+ * @param string name
22
+ * @param string category
23
+ * @param string redirectUrl (default: empty string)
24
+ * @param array pushedProducts; array of records
25
+ * @param array feedback; array of strings with labels as keys
26
+ * @param array activeQuestions; array of FACTFinder_AdvisorQuestion objects
27
+ */
28
+ public function __construct($name = '', $category = '', $redirectUrl = '', array $pushedProducts = array(), $feedback = array(), $activeQuestions = array(), $advisorTree = array()) {
29
+ $this->name = trim($name);
30
+ $this->category = trim($category);
31
+ $this->redirectUrl = trim($redirectUrl);
32
+ $this->addPushedProducts($pushedProducts);
33
+ $this->addFeedback($feedback);
34
+ $this->addActiveQuestions($activeQuestions);
35
+ $this->addToAdvisorTree($advisorTree);
36
+ }
37
+
38
+ /**
39
+ * @return string name
40
+ */
41
+ public function getName() {
42
+ return $this->name;
43
+ }
44
+
45
+ /**
46
+ * @return string url
47
+ */
48
+ public function getCategory(){
49
+ return $this->category;
50
+ }
51
+
52
+ /**
53
+ * true if a redirect link was set
54
+ *
55
+ * @return boolean
56
+ */
57
+ public function hasRedirect()
58
+ {
59
+ return !empty($this->redirectUrl);
60
+ }
61
+
62
+ /**
63
+ * @return string url
64
+ */
65
+ public function getRedirectUrl(){
66
+ return $this->redirectUrl;
67
+ }
68
+
69
+ /**
70
+ * add products to this campaign
71
+ *
72
+ * @param array of FACTFinder_Record objects
73
+ * @return void
74
+ */
75
+ public function addPushedProducts(array $pushedProducts) {
76
+ foreach ($pushedProducts AS $product) {
77
+ $this->pushedProducts[] = $product;
78
+ }
79
+ }
80
+
81
+ /**
82
+ * true if pushed products exist
83
+ *
84
+ * @return boolean
85
+ */
86
+ public function hasPushedProducts() {
87
+ return sizeof($this->pushedProducts) > 0;
88
+ }
89
+
90
+ /**
91
+ * @return array of FACTFinder_Record objects
92
+ */
93
+ public function getPushedProducts() {
94
+ return $this->pushedProducts;
95
+ }
96
+
97
+ /**
98
+ * set the feedback strings. if a feedback with the same key (label) exist, it will be overwritten
99
+ *
100
+ * @param array of string
101
+ * @return void
102
+ */
103
+ public function addFeedback(array $feedback) {
104
+ foreach($feedback AS $label => $text) {
105
+ $this->feedback[$label] = trim($text);
106
+ }
107
+ }
108
+
109
+ /**
110
+ * returns true if feedback exists. if argument is specified, this methods checks, whether there is any
111
+ * feedback text available. if a label is given, then this method only returns true, if there is a feedback text
112
+ * for this label
113
+ *
114
+ * @param string label of feedback (default: null)
115
+ * @return boolean
116
+ */
117
+ public function hasFeedback($label = null) {
118
+ if ($label != null) {
119
+ $hasFeedback = isset($this->feedback[$label]) && $this->feedback[$label] != '';
120
+ } else {
121
+ $hasFeedback = sizeof($this->feedback) > 0 && implode('', $this->feedback) != '';
122
+ }
123
+ return $hasFeedback;
124
+ }
125
+
126
+ /**
127
+ * when label is specified, only the desired feedback text will be returned or an empty string, if this text does not exist.
128
+ * if no label is set, the complete feedback array will be returned
129
+ *
130
+ * @param string $label
131
+ * @return array|string
132
+ */
133
+ public function getFeedback($label = null) {
134
+ if ($label === null) {
135
+ return $this->feedback;
136
+ } else if (isset($this->feedback[$label])) {
137
+ return $this->feedback[$label];
138
+ } else {
139
+ return '';
140
+ }
141
+ }
142
+
143
+ /**
144
+ * add active questions to this campaign
145
+ *
146
+ * @param array of FACTFinder_AdvisorQuestion objects
147
+ * @return void
148
+ */
149
+ public function addActiveQuestions(array $activeQuestions) {
150
+ foreach ($activeQuestions AS $question) {
151
+ $this->activeQuestions[] = $question;
152
+ }
153
+ }
154
+
155
+ /**
156
+ * true if advisor questions exist
157
+ *
158
+ * @return boolean
159
+ */
160
+ public function hasActiveQuestions() {
161
+ return sizeof($this->activeQuestions) > 0;
162
+ }
163
+
164
+ /**
165
+ * @return array of FACTFinder_AdvisorQuestion objects
166
+ */
167
+ public function getActiveQuestions() {
168
+ return $this->activeQuestions;
169
+ }
170
+
171
+ /**
172
+ * add questions to the advisor tree (top level) of this campaign
173
+ *
174
+ * @param array of FACTFinder_AdvisorQuestion objects
175
+ * @return void
176
+ */
177
+ public function addToAdvisorTree(array $advisorTree) {
178
+ foreach ($advisorTree AS $question) {
179
+ $this->advisorTree[] = $question;
180
+ }
181
+ }
182
+
183
+ /**
184
+ * true if advisor tree exists
185
+ *
186
+ * @return boolean
187
+ */
188
+ public function hasAdvisorTree() {
189
+ return sizeof($this->advisorTree) > 0;
190
+ }
191
+
192
+ /**
193
+ * @return array of FACTFinder_AdvisorQuestion objects
194
+ */
195
+ public function getAdvisorTree() {
196
+ return $this->advisorTree;
197
+ }
198
+ }
lib/FACTFinder/CampaignIterator.php ADDED
@@ -0,0 +1,182 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * represents the whole collection of campaigns. decorates some campaign functions to execute on every campaign.
4
+ * By iterating over an CampaignIterator you get FACTFinder_Campaign objects in the loop.
5
+ *
6
+ * @author Rudolf Batt <rb@omikron.net>
7
+ * @version $Id: CampaignIterator.php 25985 2010-06-30 15:31:53Z rb $
8
+ * @package FACTFinder\Common
9
+ */
10
+ class FACTFinder_CampaignIterator extends ArrayIterator
11
+ {
12
+ /**
13
+ * true if a redirect link exists at one of all campaigns
14
+ *
15
+ * @see FACTFinder_Campaign::hasRedirect()
16
+ * @return boolean
17
+ */
18
+ public function hasRedirect()
19
+ {
20
+ $hasRedirect = false;
21
+ foreach ($this AS $campaign) {
22
+ if ($campaign->hasRedirect()) {
23
+ $hasRedirect = true;
24
+ break;
25
+ }
26
+ }
27
+ return $hasRedirect;
28
+ }
29
+
30
+ /**
31
+ * return the first redirect of all campaigns or null if non exists
32
+ *
33
+ * @see FACTFinder_Campaign::getRedirectUrl()
34
+ * @return string url
35
+ */
36
+ public function getRedirectUrl(){
37
+ $redirectUrl = null;
38
+ foreach ($this AS $campaign) {
39
+ if ($campaign->hasRedirect()) {
40
+ $redirectUrl = $campaign->getRedirectUrl();
41
+ break;
42
+ }
43
+ }
44
+ return $redirectUrl;
45
+ }
46
+
47
+ /**
48
+ * true if pushed products exist in of all campaigns
49
+ *
50
+ * @see FACTFinder_Campaign::hasPushedProducts()
51
+ * @return boolean
52
+ */
53
+ public function hasPushedProducts() {
54
+ $hasPushedProducts = false;
55
+ foreach ($this AS $campaign) {
56
+ if ($campaign->hasPushedProducts()) {
57
+ $hasPushedProducts = true;
58
+ break;
59
+ }
60
+ }
61
+ return $hasPushedProducts;
62
+ }
63
+
64
+ /**
65
+ * decorates FACTFinder_Campaign::getPushedProducts() for all campaigns
66
+ *
67
+ * @see FACTFinder_Campaign::getPushedProducts()
68
+ * @return array of records
69
+ */
70
+ public function getPushedProducts() {
71
+ $pushedProducts = array();
72
+ foreach ($this AS $campaign) {
73
+ if ($campaign->hasPushedProducts()) {
74
+ $pushedProducts = array_merge($pushedProducts, $campaign->getPushedProducts());
75
+ }
76
+ }
77
+ return $pushedProducts;
78
+ }
79
+
80
+ /**
81
+ * decorates FACTFinder_Campaign::hasFeedback() for each campaign. return true, if one of all campaigns has feedback
82
+ * text snippets
83
+ *
84
+ * @see FACTFinder_Campaign::hasFeedback()
85
+ * @return boolean
86
+ */
87
+ public function hasFeedback($nr = null) {
88
+ $hasFeedback = false;
89
+ foreach ($this AS $campaign) {
90
+ if ($campaign->hasFeedback($nr)) {
91
+ $hasFeedback = true;
92
+ break;
93
+ }
94
+ }
95
+ return $hasFeedback;
96
+ }
97
+
98
+ /**
99
+ * decorates FACTFinder_Campaign::getFeedback() for each campaign. returnes a string of each feedback from all
100
+ * campaigns, glued together with PHP_EOL
101
+ *
102
+ * @see FACTFinder_Campaign::getFeedback()
103
+ * @param int $nr of feedback text
104
+ * @return string
105
+ */
106
+ public function getFeedback($nr) {
107
+ $feedback = '';
108
+ foreach ($this AS $campaign) {
109
+ if ($campaign->hasFeedback()) {
110
+ $feedback .= $campaign->getFeedback($nr).PHP_EOL;
111
+ }
112
+ }
113
+ return $feedback;
114
+ }
115
+
116
+ /**
117
+ * true if active advisor questions exist in any campaign
118
+ *
119
+ * @see FACTFinder_Campaign::hasActiveQuestions()
120
+ * @return boolean
121
+ */
122
+ public function hasActiveQuestions() {
123
+ $hasActiveQuestions = false;
124
+ foreach ($this AS $campaign) {
125
+ if ($campaign->hasActiveQuestions()) {
126
+ $hasActiveQuestions = true;
127
+ break;
128
+ }
129
+ }
130
+ return $hasActiveQuestions;
131
+ }
132
+
133
+ /**
134
+ * decorates FACTFinder_Campaign::getActiveQuestions() for all campaigns
135
+ *
136
+ * @see FACTFinder_Campaign::getActiveQuestions()
137
+ * @return array of records
138
+ */
139
+ public function getActiveQuestions() {
140
+ $activeQuestions = array();
141
+ foreach ($this AS $campaign) {
142
+ if ($campaign->hasActiveQuestions()) {
143
+ $activeQuestions = array_merge($activeQuestions, $campaign->getActiveQuestions());
144
+ }
145
+ }
146
+ return $activeQuestions;
147
+ }
148
+
149
+
150
+ /**
151
+ * true if an advisor tree exists in any campaign
152
+ *
153
+ * @see FACTFinder_Campaign::hasActiveQuestions()
154
+ * @return boolean
155
+ */
156
+ public function hasAdvisorTree() {
157
+ $hasAdvisorTree = false;
158
+ foreach ($this AS $campaign) {
159
+ if ($campaign->hasAdvisorTree()) {
160
+ $hasAdvisorTree = true;
161
+ break;
162
+ }
163
+ }
164
+ return $hasAdvisorTree;
165
+ }
166
+
167
+ /**
168
+ * decorates FACTFinder_Campaign::getAdvisorTree() for all campaigns
169
+ *
170
+ * @see FACTFinder_Campaign::getAdvisorTree()
171
+ * @return array of records
172
+ */
173
+ public function getAdvisorTree() {
174
+ $advisorTree = array();
175
+ foreach ($this AS $campaign) {
176
+ if ($campaign->hasAdvisorTree()) {
177
+ $advisorTree = array_merge($advisorTree, $campaign->getAdvisorTree());
178
+ }
179
+ }
180
+ return $advisorTree;
181
+ }
182
+ }
lib/FACTFinder/Configuration.php ADDED
@@ -0,0 +1,362 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * this class implements the FACTFinder configuration interface and uses the Zend_Config class. so it's like a decorator
5
+ * for the Zend_Config
6
+ *
7
+ * @package FACTFinder\Common
8
+ */
9
+ class FACTFinder_Configuration implements FACTFinder_Abstract_Configuration
10
+ {
11
+ const HTTP_AUTH = 'http';
12
+ const SIMPLE_AUTH = 'simple';
13
+ const ADVANCED_AUTH = 'advanced';
14
+
15
+ protected $zendConfig;
16
+ private $authType;
17
+ private $pageMappings;
18
+ private $serverMappings;
19
+ private $pageIgnores;
20
+ private $serverIgnores;
21
+ private $requiredPageParams;
22
+ private $requiredServerParams;
23
+
24
+ public function __construct(Zend_Config $config)
25
+ {
26
+ $this->zendConfig = $config;
27
+ }
28
+
29
+ /**
30
+ * @return string
31
+ */
32
+ public function getVersion() {
33
+ return $this->zendConfig->version;
34
+ }
35
+
36
+ /**
37
+ * @return boolean
38
+ * @deprecated
39
+ */
40
+ public function isDebugEnabled() {
41
+ return $this->zendConfig->debug == 'true';
42
+ }
43
+
44
+ /**
45
+ * @param string name
46
+ * @return string value
47
+ */
48
+ public function getCustomValue($name) {
49
+ return $this->zendConfig->$name;
50
+ }
51
+
52
+ /**
53
+ * @deprecated because of wrong spelling. use "getRequestProtocol()" instead
54
+ * @return string
55
+ */
56
+ public function getRequestProtokoll() {
57
+ return $this->zendConfig->search->protokoll;
58
+ }
59
+
60
+ /**
61
+ * @return string
62
+ */
63
+ public function getRequestProtocol() {
64
+ $protocol = $this->zendConfig->search->protocol;
65
+
66
+ // legacy code for older configurations
67
+ if (empty($protocol)) {
68
+ $protocol = $this->getRequestProtokoll();
69
+ }
70
+ return $protocol;
71
+ }
72
+
73
+ /**
74
+ * @return string
75
+ */
76
+ public function getServerAddress() {
77
+ return $this->zendConfig->search->address;
78
+ }
79
+
80
+ /**
81
+ * @return int
82
+ */
83
+ public function getServerPort() {
84
+ return $this->zendConfig->search->port;
85
+ }
86
+
87
+ /**
88
+ * @return string
89
+ */
90
+ public function getContext() {
91
+ return $this->zendConfig->search->context;
92
+ }
93
+
94
+ /**
95
+ * @return string
96
+ */
97
+ public function getChannel() {
98
+ return $this->zendConfig->search->channel;
99
+ }
100
+
101
+ /**
102
+ * @return string
103
+ */
104
+ public function getLanguage() {
105
+ return $this->zendConfig->search->language;
106
+ }
107
+
108
+ /**
109
+ * @return string
110
+ */
111
+ public function getAuthUser() {
112
+ return $this->zendConfig->search->auth->user;
113
+ }
114
+
115
+ /**
116
+ * @return string
117
+ */
118
+ public function getAuthPasswort() {
119
+ return $this->zendConfig->search->auth->password;
120
+ }
121
+
122
+ /**
123
+ * @return boolean
124
+ */
125
+ public function isHttpAuthenticationType() {
126
+ return $this->getAuthType() == self::HTTP_AUTH;
127
+ }
128
+
129
+ /**
130
+ * @return boolean
131
+ */
132
+ public function isSimpleAuthenticationType() {
133
+ return $this->getAuthType() == self::SIMPLE_AUTH;
134
+ }
135
+
136
+ /**
137
+ * @return boolean
138
+ */
139
+ public function isAdvancedAuthenticationType() {
140
+ return $this->getAuthType() == self::ADVANCED_AUTH;
141
+ }
142
+
143
+ private function getAuthType() {
144
+ if ($this->authType == null) {
145
+ $this->authType = $this->zendConfig->search->auth->type;
146
+ if ( $this->authType != self::HTTP_AUTH
147
+ && $this->authType != self::SIMPLE_AUTH
148
+ && $this->authType != self::ADVANCED_AUTH ) {
149
+ $this->authType = self::HTTP_AUTH;
150
+ }
151
+ }
152
+ return $this->authType;
153
+ }
154
+
155
+ /**
156
+ * @return string
157
+ */
158
+ public function getAdvancedAuthPrefix() {
159
+ return $this->zendConfig->search->auth->advancedPrefix;
160
+ }
161
+
162
+ /**
163
+ * @return string
164
+ */
165
+ public function getAdvancedAuthPostfix(){
166
+ return $this->zendConfig->search->auth->advancedPostfix;
167
+ }
168
+
169
+ /**
170
+ * {@inheritdoc}
171
+ *
172
+ * @return array
173
+ */
174
+ public function getPageMappings() {
175
+ if ($this->pageMappings == null) {
176
+ $this->pageMappings = array();
177
+ if ($this->zendConfig->params->client->mapping != null) {
178
+
179
+ // get mapping config as iterable variable
180
+ if ($this->zendConfig->params->client->mapping->from == null) {
181
+ $mapping = $this->zendConfig->params->client->mapping;
182
+ } else {
183
+ $mapping = array($this->zendConfig->params->client->mapping);
184
+ }
185
+
186
+ //load mappings
187
+ foreach($mapping AS $rule) {
188
+ $this->pageMappings[$rule->from] = $rule->to;
189
+ }
190
+ }
191
+ }
192
+ return $this->pageMappings;
193
+ }
194
+
195
+ /**
196
+ * {@inheritdoc}
197
+ *
198
+ * @return array
199
+ */
200
+ public function getServerMappings() {
201
+ if ($this->serverMappings == null) {
202
+ $this->serverMappings = array();
203
+ if ($this->zendConfig->params->server->mapping != null) {
204
+
205
+ // get mapping config as iterable variable
206
+ if ($this->zendConfig->params->server->mapping->from == null) {
207
+ $mapping = $this->zendConfig->params->server->mapping;
208
+ } else {
209
+ $mapping = array($this->zendConfig->params->server->mapping);
210
+ }
211
+
212
+ //load mappings
213
+ foreach($mapping AS $rule) {
214
+ $this->serverMappings[$rule->from] = $rule->to;
215
+ }
216
+ }
217
+ }
218
+ return $this->serverMappings;
219
+ }
220
+
221
+ /**
222
+ * {@inheritdoc}
223
+ *
224
+ * @return array with string as key and boolean true as value for each of them
225
+ */
226
+ public function getIgnoredPageParams() {
227
+ if ($this->pageIgnores == null) {
228
+ $this->pageIgnores = array();
229
+ if (isset($this->zendConfig->params->client->ignore)) {
230
+
231
+ // get ignore rules as iterable variable
232
+ if($this->zendConfig->params->client->ignore->name == null) {
233
+ $ignoreRules = $this->zendConfig->params->client->ignore ;
234
+ } else {
235
+ $ignoreRules = array($this->zendConfig->params->client->ignore );
236
+ }
237
+
238
+ // load ignore rules
239
+ foreach($ignoreRules AS $i) {
240
+ $this->pageIgnores[$i->name] = true;
241
+ }
242
+ }
243
+
244
+ $pageMappings = $this->getPageMappings();
245
+ foreach ($pageMappings AS $from => $to) {
246
+ $this->pageIgnores[$from] = true;
247
+ }
248
+ }
249
+ return $this->pageIgnores;
250
+ }
251
+
252
+ /**
253
+ * {@inheritdoc}
254
+ *
255
+ * @return array with string as key and boolean true as value for each of them
256
+ */
257
+ public function getIgnoredServerParams() {
258
+ if ($this->serverIgnores == null) {
259
+ $this->serverIgnores = array();
260
+ if (isset($this->zendConfig->params->server->ignore)) {
261
+
262
+ // get ignore rules as iterable variable
263
+ if($this->zendConfig->params->server->ignore->name == null) {
264
+ $ignoreRules = $this->zendConfig->params->server->ignore ;
265
+ } else {
266
+ $ignoreRules = array($this->zendConfig->params->server->ignore );
267
+ }
268
+
269
+ // load ignore rules
270
+ foreach($ignoreRules AS $i) {
271
+ $this->serverIgnores[$i->name] = true;
272
+ }
273
+ }
274
+
275
+ $serverMappings = $this->getServerMappings();
276
+ foreach ($serverMappings AS $from => $to) {
277
+ $this->serverIgnores[$from] = true;
278
+ }
279
+ }
280
+ return $this->serverIgnores;
281
+ }
282
+
283
+ /**
284
+ * {@inheritdoc}
285
+ *
286
+ * @return array string to string map (param-name as array-key; default value as array-value)
287
+ */
288
+ public function getRequiredPageParams(){
289
+ if ($this->requiredPageParams == null) {
290
+ $this->requiredPageParams = array();
291
+ if ($this->zendConfig->params->client->required != null) {
292
+
293
+ // get required params config as iterable variable
294
+ if ($this->zendConfig->params->client->required->name == null) {
295
+ $requiredParams = $this->zendConfig->params->client->required;
296
+ } else {
297
+ $requiredParams = array($this->zendConfig->params->client->required);
298
+ }
299
+
300
+ //load mappings
301
+ foreach($requiredParams AS $param) {
302
+ $this->requiredPageParams[$param->name] = $param->default;
303
+ }
304
+ }
305
+ }
306
+ return $this->requiredPageParams;
307
+ }
308
+
309
+ /**
310
+ * {@inheritdoc}
311
+ *
312
+ * @return array string to string map (param-name as array-key; default value as array-value)
313
+ */
314
+ function getRequiredServerParams(){
315
+ if ($this->requiredServerParams == null) {
316
+ $this->requiredServerParams = array();
317
+ if ($this->zendConfig->params->server->required != null) {
318
+
319
+ // get required params config as iterable variable
320
+ if ($this->zendConfig->params->server->required->name == null) {
321
+ $requiredParams = $this->zendConfig->params->server->required;
322
+ } else {
323
+ $requiredParams = array($this->zendConfig->params->server->required);
324
+ }
325
+
326
+ //load mappings
327
+ foreach($requiredParams AS $param) {
328
+ $this->requiredServerParams[$param->name] = $param->default;
329
+ }
330
+ }
331
+ }
332
+ return $this->requiredServerParams;
333
+ }
334
+
335
+
336
+ /**
337
+ * {@inheritdoc}
338
+ *
339
+ * @return string
340
+ */
341
+ function getPageContentEncoding() {
342
+ return $this->zendConfig->encoding->pageContent;
343
+ }
344
+
345
+ /**
346
+ * {@inheritdoc}
347
+ *
348
+ * @return string
349
+ */
350
+ function getPageUrlEncoding() {
351
+ return $this->zendConfig->encoding->pageURI;
352
+ }
353
+
354
+ /**
355
+ * {@inheritdoc}
356
+ *
357
+ * @return string
358
+ */
359
+ function getServerUrlEncoding() {
360
+ return $this->zendConfig->encoding->serverURI;
361
+ }
362
+ }
lib/FACTFinder/EncodingHandler.php ADDED
@@ -0,0 +1,209 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * this class handles the different issues of encoding between the values of page-url, server-url, result and pagecontent
5
+ *
6
+ * @package FACTFinder\Common
7
+ */
8
+ class FACTFinder_EncodingHandler
9
+ {
10
+ protected $convertMethod;
11
+
12
+ protected $pageContentEncoding;
13
+ protected $pageUrlEncoding;
14
+ protected $serverUrlEncoding;
15
+
16
+ protected $log;
17
+
18
+ public function __construct(FACTFinder_Abstract_Configuration $config)
19
+ {
20
+ $this->log = FF::getLogger();
21
+
22
+ $this->pageContentEncoding = $config->getPageContentEncoding();
23
+ $this->pageUrlEncoding = $config->getPageUrlEncoding();
24
+ $this->serverUrlEncoding = $config->getServerUrlEncoding();
25
+
26
+ if (function_exists('iconv')) {
27
+ $this->convertMethod = 'iConvert';
28
+ } else {
29
+ $this->convertMethod = 'utf8Convert';
30
+ }
31
+ }
32
+
33
+ /**
34
+ * converts the string from "inCharset" encoding into "outCharset" encoding. if the running php have no iconv support,
35
+ * the utf8_encode/decode are used, so only the encodings "utf-8" and "iso-8859-?" can be used
36
+ *
37
+ * @param input charset
38
+ * @param output charset
39
+ * @param string which should be converted
40
+ * @return string in specified output charset
41
+ * @throws exception for not supported charset
42
+ */
43
+ public function convert($inCharset, $outCharset, $string)
44
+ {
45
+ return $this->{$this->convertMethod}($inCharset, $outCharset, $string);
46
+ }
47
+
48
+ /**
49
+ * uses iconvert to convert string
50
+ *
51
+ * @link http://bg.php.net/manual/en/book.iconv.php
52
+ * @param input charset
53
+ * @param output charset
54
+ * @param string which should be converted
55
+ * @return string in specified output charset
56
+ */
57
+ protected function iConvert($inCharset, $outCharset, $string)
58
+ {
59
+ // see http://de2.php.net/manual/de/function.iconv.php to understand '//IGNORE'
60
+ return ($inCharset == $outCharset || empty($inCharset) || empty($outCharset)) ? $string : iconv($inCharset, $outCharset.'//IGNORE', $string);
61
+ }
62
+
63
+ /**
64
+ * uses utf8-convert functions to convert string
65
+ *
66
+ * @param input charset
67
+ * @param output charset
68
+ * @param string which should be converted
69
+ * @return string in specified output charset
70
+ * @throws exception for not supported charset
71
+ */
72
+ protected function utf8Convert($inCharset, $outCharset, $string)
73
+ {
74
+ if (strtolower($inCharset) != strtolower($outCharset) && !empty($inCharset) && !empty($outCharset)) {
75
+ if (strtolower($inCharset) == 'utf-8') {
76
+ $string = utf8_decode($string);
77
+ } else if (strtolower($outCharset) == 'utf-8') {
78
+ $string = utf8_encode($string);
79
+ } else {
80
+ $this->log->error("Could not convert between non-UTF-8 charsets.");
81
+ throw new Exception("can not handle $inCharset to $outCharset conversion!");
82
+ }
83
+ }
84
+ return $string;
85
+ }
86
+
87
+ /**
88
+ * converts the url data, to display correctly at the page
89
+ *
90
+ * @param string|array data
91
+ * @return string|array converted data
92
+ */
93
+ public function encodeUrlForPage($data)
94
+ {
95
+ // notice: urldecode is not needed, because php decodes the url automatically
96
+ if ($this->pageUrlEncoding != $this->pageContentEncoding) {
97
+ if (is_array($data)) {
98
+ $returnData = array();
99
+ foreach ($data AS $key => $value) {
100
+ $key = $this->convert($this->pageUrlEncoding, $this->pageContentEncoding, $key);
101
+ $returnData[$key] = $this->convert($this->pageUrlEncoding, $this->pageContentEncoding, $value);
102
+ }
103
+ } else if (is_string($data)) {
104
+ $returnData = $this->convert($this->pageUrlEncoding, $this->pageContentEncoding, $data);
105
+ }
106
+ } else {
107
+ $returnData = $data;
108
+ }
109
+ return $returnData;
110
+ }
111
+
112
+ /**
113
+ * converts the url data from the server result for the page url
114
+ *
115
+ * @param string|array data
116
+ * @return string|array converted data
117
+ */
118
+ public function encodeServerUrlForPageUrl($data)
119
+ {
120
+ // notice: urldecode is not needed, because the parameters parser is already doing that
121
+ if ($this->serverUrlEncoding != $this->pageUrlEncoding) {
122
+ if (is_array($data)) {
123
+ $returnData = array();
124
+ foreach ($data AS $key => $value) {
125
+ $key = $this->convert($this->serverUrlEncoding, $this->pageUrlEncoding, $key);
126
+ $returnData[$key] = $this->convert($this->serverUrlEncoding, $this->pageUrlEncoding, $value);
127
+ }
128
+ } else if (is_string($data)) {
129
+ $returnData = $this->convert($this->serverUrlEncoding, $this->pageUrlEncoding, $data);
130
+ }
131
+ } else {
132
+ $returnData = $data;
133
+ }
134
+ return $returnData;
135
+ }
136
+
137
+ /**
138
+ * converts the data from the server result for the page content
139
+ *
140
+ * @param string|array data
141
+ * @return string|array converted data
142
+ */
143
+ public function encodeServerContentForPage($data)
144
+ {
145
+ // server result data is always utf-8
146
+ if (strtolower($this->pageContentEncoding) != 'utf-8') {
147
+ if (is_array($data)) {
148
+ $returnData = array();
149
+ foreach ($data AS $key => $value) {
150
+ $key = $this->convert('UTF-8', $this->pageContentEncoding, $key);
151
+ $returnData[$key] = $this->convert('UTF-8', $this->pageContentEncoding, $value);
152
+ }
153
+ } else if (is_string($data)) {
154
+ $returnData = $this->convert('UTF-8', $this->pageContentEncoding, $data);
155
+ }
156
+ } else {
157
+ $returnData = $data;
158
+ }
159
+ return $returnData;
160
+ }
161
+
162
+ /**
163
+ * converts the data for the server url
164
+ *
165
+ * @param string|array data
166
+ * @return string|array converted data
167
+ */
168
+ public function encodeForServerUrl($data)
169
+ {
170
+ if ($this->pageContentEncoding != $this->serverUrlEncoding) {
171
+ if (is_array($data)) {
172
+ $returnData = array();
173
+ foreach ($data AS $key => $value) {
174
+ $key = $this->convert($this->pageContentEncoding, $this->serverUrlEncoding, $key);
175
+ $returnData[$key] = $this->convert($this->pageContentEncoding, $this->serverUrlEncoding, $value);
176
+ }
177
+ } else if (is_string($data)) {
178
+ $returnData = $this->convert($this->pageContentEncoding, $this->serverUrlEncoding, $data);
179
+ }
180
+ } else {
181
+ $returnData = $data;
182
+ }
183
+ return $returnData;
184
+ }
185
+
186
+ /**
187
+ * converts the data from the page for the page url
188
+ *
189
+ * @param string|array data
190
+ * @return string|array converted data
191
+ */
192
+ public function encodeForPageUrl($data)
193
+ {
194
+ if ($this->pageContentEncoding != $this->pageUrlEncoding) {
195
+ if (is_array($data)) {
196
+ $returnData = array();
197
+ foreach ($data AS $key => $value) {
198
+ $key = $this->convert($this->pageContentEncoding, $this->pageUrlEncoding, $key);
199
+ $returnData[$key] = $this->convert($this->pageContentEncoding, $this->pageUrlEncoding, $value);
200
+ }
201
+ } else if (is_string($data)) {
202
+ $returnData = $this->convert($this->pageContentEncoding, $this->pageUrlEncoding, $data);
203
+ }
204
+ } else {
205
+ $returnData = $data;
206
+ }
207
+ return $returnData;
208
+ }
209
+ }
lib/FACTFinder/Http/DataProvider.php ADDED
@@ -0,0 +1,291 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * this data provider loads the data via http
5
+ *
6
+ * @author Rudolf Batt <rb@omikron.net>
7
+ * @version $Id: DataProvider.php 25893 2010-06-29 08:19:43Z rb $
8
+ * @package FACTFinder\Http
9
+ */
10
+ class FACTFinder_Http_DataProvider extends FACTFinder_Abstract_DataProvider
11
+ {
12
+ protected $data;
13
+ protected $previousUrl;
14
+ protected $httpHeader = array();
15
+ protected $curlOptions = array(
16
+ CURLOPT_RETURNTRANSFER => true,
17
+ CURLOPT_SSL_VERIFYPEER => false,
18
+ CURLOPT_SSL_VERIFYHOST => false,
19
+ CURLOPT_CONNECTTIMEOUT => 2,
20
+ CURLOPT_TIMEOUT => 4
21
+ );
22
+
23
+ /**
24
+ * this implementation of the data provider uses the type as request path in addition to the request context path.
25
+ * please ensure that this is the full action name, i.e. "Search.ff"
26
+ *
27
+ * @param string type
28
+ */
29
+ public function setType($type)
30
+ {
31
+ $this->type = $type;
32
+ }
33
+
34
+ /**
35
+ * set a option for a cURL request like described at {@link http://php.net/manual/en/function.curl-setopt.php}.
36
+ * The second parameter can be set to false, so the option will not be overwritten if it already exists
37
+ *
38
+ * @link http://php.net/manual/en/function.curl-setopt.php
39
+ * @param the option key (should be a cURL constant)
40
+ * @param the option value
41
+ * @param boolean whether to overwrite existing options or not. optional, default = true
42
+ * @return void
43
+ */
44
+ public function setCurlOption($option, $value, $overwriteExisting = true) {
45
+ if ($overwriteExisting || !isset($this->curlOptions[$option])) {
46
+ $this->curlOptions[$option] = $value;
47
+ }
48
+ }
49
+
50
+ /**
51
+ * Set multiple options for a cURL request like described at {@link http://php.net/manual/en/function.curl-setopt.php}
52
+ *
53
+ * @link http://php.net/manual/en/function.curl-setopt.php
54
+ * @param array of options
55
+ * @return void
56
+ */
57
+ public function setCurlOptions(array $options) {
58
+ foreach($options AS $option => $value) {
59
+ $this->setCurlOption($option, $value);
60
+ }
61
+ }
62
+
63
+ /**
64
+ * add an array of HTTP header fields in the format array('Content-type: text/plain', 'Content-length: 100')
65
+ *
66
+ * @param array $httpHeader
67
+ * @return void
68
+ */
69
+ public function addHttpHeaderFields(array $httpHeader) {
70
+ $this->httpHeader = array_merge($this->httpHeader, $httpHeader);
71
+ }
72
+
73
+ /**
74
+ * {@inheritdoc}
75
+ * this implementation returns the data as string, no matter what content type set at the http response
76
+ *
77
+ * @return string data
78
+ */
79
+ public function getData()
80
+ {
81
+ $url = $this->getAuthenticationUrl();
82
+ if ($this->data == null || $url != $this->previousUrl) {
83
+ $this->previousUrl = $url;
84
+ $this->data = $this->loadResponse($url);
85
+ }
86
+ return $this->data;
87
+ }
88
+
89
+ /**
90
+ * this function sends the request to the server and loads the response data
91
+ *
92
+ * @throws Exception on connection error
93
+ * @return response data
94
+ **/
95
+ protected function loadResponse($url)
96
+ {
97
+ if ($this->type == null) {
98
+ $this->log->error("Request type missing.");
99
+ throw new Exception('request type not set! can not do a request without knowing the type.');
100
+ }
101
+
102
+ $config = $this->getConfig();
103
+ if ($config->getLanguage() != '') {
104
+ $this->addHttpHeaderFields(array('Accept-Language: ' . $config->getLanguage()));
105
+ }
106
+
107
+ if ($this->getConfig()->isDebugEnabled()) {
108
+ $url .= '&verbose=true';
109
+ if (isset($_SERVER['HTTP_REFERER'])) $this->setCurlOption(CURLOPT_REFERER, $_SERVER['HTTP_REFERER'], false);
110
+ }
111
+ return $this->sendRequest($url);
112
+ }
113
+
114
+ /**
115
+ * this function returns the request url with the correct authentication method (set by the configuration).
116
+ *
117
+ * @return string url
118
+ */
119
+ public function getAuthenticationUrl() {
120
+ $config = $this->getConfig();
121
+ if ($config->isHttpAuthenticationType()) {
122
+ $url = $this->getHttpAuthenticationUrl();
123
+ } else if ($config->isSimpleAuthenticationType()) {
124
+ $url = $this->getSimpleAuthenticationUrl();
125
+ } else if ($config->isAdvancedAuthenticationType()) {
126
+ $url = $this->getAdvancedAuthenticationUrl();
127
+ } else {
128
+ $url = $this->getNonAuthenticationUrl();
129
+ }
130
+ return $url;
131
+ }
132
+
133
+ /**
134
+ * send request and return response data
135
+ *
136
+ * @param string url
137
+ * @return string returned http body
138
+ */
139
+ protected function sendRequest($url)
140
+ {
141
+ $this->log->info("Trying to send request to ".$url."...");
142
+ $cResource = curl_init($url);
143
+
144
+ if (!empty($this->httpHeader)) {
145
+ $this->curlOptions[CURLOPT_HTTPHEADER] = $this->httpHeader;
146
+ }
147
+
148
+ if (sizeof($this->curlOptions) > 0) {
149
+ curl_setopt_array($cResource, $this->curlOptions);
150
+ }
151
+
152
+ $response = curl_exec($cResource);
153
+ $httpCode = curl_getinfo($cResource, CURLINFO_HTTP_CODE);
154
+ $curlErr = curl_error($cResource);
155
+ curl_close($cResource);
156
+
157
+ if (intval($httpCode) >= 400) {
158
+ $this->log->error("Conntection failed. HTTP code: $httpCode");
159
+ throw new Exception("Connection failed. HTTP code: $httpCode", $httpCode);
160
+ } else if ($httpCode == 0) {
161
+ $this->log->error("Connection refused. $curlErr");
162
+ throw new Exception("Connection refused. $curlErr");
163
+ } else if (floor(intval($httpCode) / 100) == 2) { // all successful status codes (2**)
164
+ $this->log->info("Received response from ".$url.".");
165
+ }
166
+
167
+ return $response;
168
+ }
169
+
170
+ /**
171
+ * get url with advanced authentication encryption
172
+ *
173
+ * @return string url
174
+ */
175
+ protected function getAdvancedAuthenticationUrl() {
176
+ $config = $this->getConfig();
177
+ $params = $this->getParams();
178
+ $this->log->info("Server Request Params: ".http_build_query($params, '', ', '));
179
+
180
+ $params['channel'] = $this->getChannel($params, $config);
181
+
182
+ $ts = time() . '000'; //millisecondes needed
183
+ $prefix = $config->getAdvancedAuthPrefix();
184
+ $postfix = $config->getAdvancedAuthPostfix();
185
+ $authParams = "timestamp=$ts&username=".$config->getAuthUser()
186
+ . '&password=' . md5($prefix . $ts . md5($config->getAuthPasswort()) . $postfix);
187
+
188
+ $url = $config->getRequestProtocol() . '://'
189
+ . $config->getServerAddress() . ':' . $config->getServerPort() . '/'
190
+ . $config->getContext() . '/'.$this->type.'?' . http_build_query($params, '', '&')
191
+ . (count($params)?'&':'') . $authParams;
192
+
193
+ // The following line removes all []-indices from array parameters, because tomcat doesn't need them
194
+ $url = preg_replace("/%5B[A-Za-z0-9]*%5D/", "", $url);
195
+ $this->log->info("Request Url: ".$url);
196
+ return $url;
197
+ }
198
+
199
+ /**
200
+ * get url with simple authentication encryption
201
+ *
202
+ * @return string url
203
+ */
204
+ protected function getSimpleAuthenticationUrl() {
205
+ $config = $this->getConfig();
206
+ $params = $this->getParams();
207
+ $this->log->info("Server Request Params: ".http_build_query($params, '', ', '));
208
+
209
+ $params['channel'] = $this->getChannel($params, $config);
210
+
211
+ $ts = time() . '000'; //millisecondes needed but won't be considered
212
+ $authParams = "timestamp=$ts&username=".$config->getAuthUser()
213
+ . '&password=' . md5($config->getAuthPasswort());
214
+
215
+ $url = $config->getRequestProtocol() . '://'
216
+ . $config->getServerAddress() . ':' . $config->getServerPort() . '/'
217
+ . $config->getContext() . '/'.$this->type.'?' . http_build_query($params, '', '&')
218
+ . (count($params)?'&':'') . $authParams;
219
+
220
+ // The following line removes all []-indices from array parameters, because tomcat doesn't need them
221
+ $url = preg_replace("/%5B[A-Za-z0-9]*%5D/", "", $url);
222
+ $this->log->info("Request Url: ".$url);
223
+ return $url;
224
+ }
225
+
226
+ /**
227
+ * get url with http authentication
228
+ *
229
+ * @return string url
230
+ */
231
+ protected function getHttpAuthenticationUrl() {
232
+ $config = $this->getConfig();
233
+ $params = $this->getParams();
234
+ $this->log->info("Server Request Params: ".http_build_query($params, '', ', '));
235
+
236
+ $params['channel'] = $this->getChannel($params, $config);
237
+
238
+ $auth = $config->getAuthUser() . ':' . $config->getAuthPasswort() . '@';
239
+ if ($auth == ':@') $auth = '';
240
+
241
+ $url = $config->getRequestProtocol() . '://' . $auth
242
+ . $config->getServerAddress() . ':' . $config->getServerPort() . '/'
243
+ . $config->getContext() . '/' . $this->type . (count($params)?'?':'')
244
+ . http_build_query($params, '', '&');
245
+
246
+ // The following line removes all []-indices from array parameters, because tomcat doesn't need them
247
+ $url = preg_replace("/%5B[A-Za-z0-9]*%5D/", "", $url);
248
+ $this->log->info("Request Url: ".$url);
249
+ return $url;
250
+ }
251
+
252
+ /**
253
+ * get url with no authentication.
254
+ *
255
+ * @return string url
256
+ */
257
+ public function getNonAuthenticationUrl() {
258
+ $config = $this->getConfig();
259
+ $params = $this->getParams();
260
+ $this->log->info("Server Request Params: ".http_build_query($params, '', ', '));
261
+
262
+ $params['channel'] = $this->getChannel($params, $config);
263
+
264
+ $url = $config->getRequestProtocol() . '://'
265
+ . $config->getServerAddress() . ':' . $config->getServerPort() . '/'
266
+ . $config->getContext() . '/' . $this->type . (count($params)?'?':'')
267
+ . http_build_query($params, '', '&');
268
+
269
+ // The following line removes all []-indices from array parameters, because tomcat doesn't need them
270
+ $url = preg_replace("/%5B[A-Za-z0-9]*%5D/", "", $url);
271
+ $this->log->info("Request Url: ".$url);
272
+ return $url;
273
+ }
274
+
275
+ /**
276
+ * get channel from params or config (params override config)
277
+ *
278
+ * @param array parameterse
279
+ * @FACTFinderAbstractConfiguration config
280
+ * @return string channel
281
+ */
282
+ protected function getChannel($params, $config) {
283
+ $channel = '';
284
+ if (!empty($params['channel'])) {
285
+ $channel = $params['channel'];
286
+ } else if($config->getChannel() != '') {
287
+ $channel = $config->getChannel();
288
+ }
289
+ return $channel;
290
+ }
291
+ }
lib/FACTFinder/Http/DummyProvider.php ADDED
@@ -0,0 +1,130 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * this data provider loads the data from local static xml files
5
+ * it is only intended to be used for testing
6
+ *
7
+ * @author Rudolf Batt <rb@omikron.net>, Martin Buettner <martin.buettner@omikron.net>
8
+ * @version $Id: DummyProvider.php 44086 2012-02-29 17:19:43Z martin.buettner $
9
+ * @package FACTFinder\Xml65
10
+ */
11
+ class FACTFinder_Http_DummyProvider extends FACTFinder_Abstract_DataProvider
12
+ {
13
+ protected $data;
14
+ protected $previousFileName;
15
+
16
+ protected $fileLocation;
17
+
18
+ public function setFileLocation($loc)
19
+ {
20
+ $this->fileLocation = substr($loc, -1) == DS ? $loc : $loc.DS;
21
+ }
22
+
23
+ /**
24
+ * we just offer this function, for compatibility with the DataProvider API
25
+ *
26
+ * @link http://php.net/manual/en/function.curl-setopt.php
27
+ * @param the option key (should be a cURL constant)
28
+ * @param the option value
29
+ * @param boolean whether to overwrite existing options or not. optional, default = true
30
+ * @return void
31
+ */
32
+ public function setCurlOption($option, $value, $overwriteExisting = true) {
33
+ return;
34
+ }
35
+
36
+ /**
37
+ * we just offer this function, for compatibility with the DataProvider API
38
+ *
39
+ * @link http://php.net/manual/en/function.curl-setopt.php
40
+ * @param array of options
41
+ * @return void
42
+ */
43
+ public function setCurlOptions(array $options) {
44
+ return;
45
+ }
46
+
47
+ /**
48
+ * this implementation of the data provider uses the type as request path in addition to the request context path.
49
+ * please ensure that this is the full action name, i.e. "Search.ff"
50
+ *
51
+ * @param string type
52
+ */
53
+ public function setType($type)
54
+ {
55
+ $this->type = $type;
56
+ }
57
+
58
+ /**
59
+ * {@inheritdoc}
60
+ * this implementation returns the data as string
61
+ *
62
+ * @return string data
63
+ */
64
+ public function getData()
65
+ {
66
+ $fileName = $this->getFileName();
67
+ if ($this->data == null || $fileName != $this->previousFileName) {
68
+ $this->previousFileName = $fileName;
69
+ $this->data = $this->loadFileContent($fileName);
70
+ }
71
+ return $this->data;
72
+ }
73
+
74
+ /**
75
+ * this function loads the correct file and returns its contents
76
+ *
77
+ * @throws Exception on connection error
78
+ * @return response data
79
+ **/
80
+ protected function loadFileContent($fileName)
81
+ {
82
+ return file_get_contents($fileName);
83
+ }
84
+
85
+ protected function getFileName()
86
+ {
87
+ if ($this->type == null) {
88
+ $this->log->error("Request type missing.");
89
+ throw new Exception('request type not set! can not do a request without knowing the type.');
90
+ }
91
+
92
+ // Remove ".ff" from the type name
93
+ $fileName = substr_replace($this->type, '', '-3')."_";
94
+ $config = $this->getConfig();
95
+ $params = $this->getParams();
96
+ unset($params["format"]);
97
+ unset($params["user"]);
98
+ unset($params["pw"]);
99
+ unset($params["timestamp"]);
100
+ unset($params["channel"]);
101
+
102
+ ksort($params, SORT_STRING);
103
+ $fileName .= http_build_query($params, '', '_');
104
+ $fileName .= ".xml";
105
+
106
+ // The following line removes all []-indices from array parameters, because tomcat doesn't need them
107
+ $fileName = preg_replace("/%5B[A-Za-z0-9]*%5D/", "", $fileName);
108
+
109
+ $this->log->info("Trying to load ".$this->fileLocation.$fileName);
110
+
111
+ return $this->fileLocation.$fileName;
112
+ }
113
+
114
+ /**
115
+ * get channel from params or config (params override config)
116
+ *
117
+ * @param array parameterse
118
+ * @FACTFinderAbstractConfiguration config
119
+ * @return string channel
120
+ **/
121
+ protected function getChannel($params, $config) {
122
+ $channel = '';
123
+ if (!empty($params['channel'])) {
124
+ $channel = $params['channel'];
125
+ } else if($config->getChannel() != '') {
126
+ $channel = $config->getChannel();
127
+ }
128
+ return $channel;
129
+ }
130
+ }
lib/FACTFinder/Http/ParallelDataProvider.php ADDED
@@ -0,0 +1,159 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * contains classes to make multiple http requests at the same time
4
+ *
5
+ * @author Rudolf Batt <rb@omikron.net>
6
+ * @version $Id: DataProvider.php 25893 2010-06-29 08:19:43Z rb $
7
+ * @package FACTFinder\Http
8
+ */
9
+
10
+ /**
11
+ * this is an anonymous inner class which can't be used successfully from the outside
12
+ */
13
+ class FACTFinder_Http_DataProviderProxy extends FACTFinder_Http_DataProvider
14
+ {
15
+ private $id;
16
+ private $master;
17
+
18
+ public function register($id, FACTFinder_Http_ParallelDataProvider $master) {
19
+ $this->id = $id;
20
+ $this->master = $master;
21
+ }
22
+
23
+ public function getData() {
24
+ return $this->master->getData($this->id);
25
+ }
26
+
27
+ public function getCurlOptions() {
28
+ return $this->curlOptions;
29
+ }
30
+
31
+ public function getHttpHeader() {
32
+ return $this->httpHeader;
33
+ }
34
+ }
35
+
36
+ // Exception type needed for parallel data provider
37
+ class DataNotLoadedException extends Exception {}
38
+
39
+ /**
40
+ * this data provider makes multiple http request at the same time
41
+ * @TODO: describe usage
42
+ */
43
+ class FACTFinder_Http_ParallelDataProvider
44
+ {
45
+ protected static $instance;
46
+ protected static $dataProvider = array();
47
+ protected static $dataLoaded = false;
48
+
49
+ protected $data;
50
+
51
+ /**
52
+ * singleton
53
+ */
54
+ private function __construct() {}
55
+
56
+ /**
57
+ * @return FACTFinder_Abstract_DataProvider
58
+ */
59
+ public static function getDataProvider(array $params = null, FACTFinder_Abstract_Configuration $config = null) {
60
+ if (self::$instance == null) {
61
+ self::$instance = new FACTFinder_Http_ParallelDataProvider();
62
+ }
63
+ $id = 'proxy' . count(self::$dataProvider); // use prefix so the id is a string
64
+ self::$dataProvider[$id] = new FACTFinder_Http_DataProviderProxy($params, $config);
65
+ self::$dataProvider[$id]->register($id, self::$instance);
66
+
67
+ return self::$dataProvider[$id];
68
+ }
69
+
70
+ /**
71
+ * this function sends all request to the server and loads the response data
72
+ *
73
+ * @return void
74
+ **/
75
+ public static function loadAllData()
76
+ {
77
+ if (self::$instance == null) {
78
+ throw new Exception("no dataprovider initialized");
79
+ }
80
+
81
+ // TODO: optimize:
82
+ // - deny multiple loading of single requests that were already loaded
83
+ // - warn if several loadings were done
84
+ // - add logging
85
+
86
+ // init handles
87
+ $multiHandle = curl_multi_init();
88
+ $handles = self::initHandles($multiHandle);
89
+ $data = self::executeHandles($multiHandle, $handles);
90
+
91
+ self::$instance->setData($data);
92
+ self::$dataLoaded = true;
93
+ }
94
+
95
+ protected static function initHandles($multiHandle) {
96
+ $handles = array();
97
+ foreach(self::$dataProvider AS $id => $dataProvider) {
98
+ $handle = curl_init($dataProvider->getAuthenticationUrl());
99
+
100
+ $curlOptions = $dataProvider->getCurlOptions();
101
+ $curlOptions[CURLOPT_HTTPHEADER] = $dataProvider->getHttpHeader();
102
+ $curlOptions[CURLOPT_RETURNTRANSFER] = true; // this is a must have option, so the data can be saved
103
+ curl_setopt_array($handle, $curlOptions);
104
+
105
+ $handles[$id] = $handle;
106
+ curl_multi_add_handle($multiHandle,$handle);
107
+ }
108
+ return $handles;
109
+ }
110
+
111
+ protected static function executeHandles($multiHandle, $handles) {
112
+ //execute the handles
113
+ $active = null;
114
+ do {
115
+ $mrc = curl_multi_exec($multiHandle, $active);
116
+ } while ($mrc == CURLM_CALL_MULTI_PERFORM);
117
+
118
+ while ($active && $mrc == CURLM_OK) {
119
+ if (curl_multi_select($multiHandle) != -1) {
120
+ do {
121
+ $mrc = curl_multi_exec($multiHandle, $active);
122
+ } while ($mrc == CURLM_CALL_MULTI_PERFORM);
123
+ }
124
+ }
125
+
126
+ // TODO: read data which is already loaded while the other data is still loading (is this possible?)
127
+ // TODO: handle errors
128
+
129
+ //close the handles
130
+ $data = array();
131
+ foreach($handles AS $id => $handle) {
132
+ $data[$id] = curl_multi_getcontent($handle);
133
+ curl_multi_remove_handle($multiHandle, $handle);
134
+ }
135
+ curl_multi_close($multiHandle);
136
+ return $data;
137
+ }
138
+
139
+ /**
140
+ *
141
+ * internal method to apply data to
142
+ */
143
+ protected function setData(array $data) {
144
+ $this->data = $data;
145
+ }
146
+
147
+ /**
148
+ * this method is called by the proxy data providers on the one and only existing instance
149
+ *
150
+ * @return string data
151
+ */
152
+ public function getData($id)
153
+ {
154
+ if (!self::$dataLoaded) {
155
+ throw new DataNotLoadedException("Implementation Error: please use 'FACTFinder_Http_ParallelDataProvider::loadAllData' before trying to get data");
156
+ }
157
+ return isset($this->data[$id]) ? $this->data[$id] : null;
158
+ }
159
+ }
lib/FACTFinder/Http/ScicAdapter.php ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * http scic adapater
5
+ *
6
+ * @author Rudolf Batt <rb@omikron.net>
7
+ * @version $Id: ScicAdapter.php 25893 2010-06-29 08:19:43Z rb $
8
+ * @package FACTFinder\Http
9
+ */
10
+ class FACTFinder_Http_ScicAdapter extends FACTFinder_Abstract_ScicAdapter
11
+ {
12
+ /**
13
+ * {@inheritdoc}
14
+ */
15
+ protected function init() {
16
+ $this->log->info("Initializing new SCIC adapter.");
17
+ $this->getDataProvider()->setType('SCIC.ff');
18
+ }
19
+
20
+ /**
21
+ * {@inheritdoc}
22
+ *
23
+ * @return boolean $success
24
+ */
25
+ protected function applyTracking() {
26
+ $success = trim($this->getData());
27
+ return $success == 'true';
28
+ }
29
+ }
lib/FACTFinder/Http/SuggestAdapter.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * this suggest adapter requests the raw suggest data
5
+ *
6
+ * @author Rudolf Batt <rb@omikron.net>
7
+ * @version $Id: SuggestAdapter.php 25893 2010-06-29 08:19:43Z rb $
8
+ * @package FACTFinder\Http
9
+ */
10
+ class FACTFinder_Http_SuggestAdapter extends FACTFinder_Abstract_SuggestAdapter
11
+ {
12
+ /**
13
+ * {@inheritdoc}
14
+ */
15
+ protected function init()
16
+ {
17
+ $this->log->info("Initializing new suggest adapter.");
18
+ $this->getDataProvider()->setType('Suggest.ff');
19
+ $this->getDataProvider()->setCurlOptions(array(
20
+ CURLOPT_CONNECTTIMEOUT => 1,
21
+ CURLOPT_TIMEOUT => 2
22
+ ));
23
+ }
24
+
25
+ /**
26
+ * {@inheritdoc}
27
+ * this implementation returns raw suggestions strings
28
+ *
29
+ * @return string raw data
30
+ */
31
+ protected function createSuggestions()
32
+ {
33
+ return $this->getData();
34
+ }
35
+ }
lib/FACTFinder/Item.php ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * an factfinder item is a simple selectable item on a website, so it is represented by a value and an url
5
+ * it is NOT defined in this class, what this item affects on the website
6
+ *
7
+ * @author Rudolf Batt <rb@omikron.net>
8
+ * @version $Id: Item.php 25893 2010-06-29 08:19:43Z rb $
9
+ * @package FACTFinder\Common
10
+ **/
11
+ class FACTFinder_Item
12
+ {
13
+ private $value;
14
+ private $url;
15
+ private $isSelected;
16
+
17
+ /**
18
+ * @param string value
19
+ * @param string url
20
+ * @param boolean is selected (default: false)
21
+ */
22
+ public function __construct($value, $url, $isSelected = false){
23
+ $this->value = strval($value);
24
+ $this->url = strval($url);
25
+ $this->isSelected = $isSelected == true;
26
+ }
27
+
28
+ /**
29
+ * @return string
30
+ */
31
+ public function getValue() {
32
+ return $this->value;
33
+ }
34
+
35
+ /**
36
+ * @return string
37
+ */
38
+ public function getUrl() {
39
+ return $this->url;
40
+ }
41
+
42
+ /**
43
+ * @return boolean
44
+ */
45
+ public function isSelected() {
46
+ return $this->isSelected;
47
+ }
48
+ }
lib/FACTFinder/Loader.php ADDED
@@ -0,0 +1,185 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * boot strap file which should be called on every request
4
+ * it defines some basic constants and loads the autoloader class, which handles the classloading,
5
+ * constructing and holds the singletons
6
+ *
7
+ * @author Rudolf Batt <rb@omikron.net>
8
+ * @version $Id: Loader.php 25893 2010-06-29 08:19:43Z rb $
9
+ * @package FACTFinder\Common
10
+ */
11
+
12
+ /**
13
+ * short cut for the constant DIRECTORY_SEPARATOR
14
+ */
15
+ if (!defined('DS')) {
16
+ define('DS', DIRECTORY_SEPARATOR);
17
+ }
18
+
19
+ /**
20
+ * contains the complete lib directory path
21
+ */
22
+ if (!defined('LIB_DIR')) {
23
+ define('LIB_DIR', dirname(dirname(__FILE__)));
24
+ }
25
+
26
+ /**
27
+ * set as include path if this is not the case yet
28
+ */
29
+ $includePaths = explode(PATH_SEPARATOR, get_include_path());
30
+ if ( array_search(LIB_DIR, $includePaths, true) === false ) {
31
+ set_include_path( get_include_path() . PATH_SEPARATOR . LIB_DIR);
32
+ }
33
+ spl_autoload_register(array('FACTFinder_Loader', 'autoload'));
34
+
35
+ // don't know, whether I should do that
36
+ if (function_exists('__autoload') && array_search('__autoload', spl_autoload_functions()) === false) {
37
+ spl_autoload_register('__autoload');
38
+ }
39
+
40
+ /**
41
+ * shortcut / alias for the loader class
42
+ *
43
+ * @author Rudolf Batt <rb@omikron.net>
44
+ */
45
+ final class FF extends FACTFinder_Loader{}
46
+
47
+
48
+ /**
49
+ * handles different loading tasks
50
+ *
51
+ * @author Rudolf Batt <rb@omikron.net>
52
+ */
53
+ class FACTFinder_Loader
54
+ {
55
+ protected static $singletons = array();
56
+ protected static $classNames = array();
57
+ protected static $logger = null;
58
+
59
+ public static function autoload($classname)
60
+ {
61
+ $filename = self::getFilename($classname);
62
+ if (file_exists($filename)) {
63
+ include_once $filename;
64
+ }
65
+ }
66
+
67
+ private static function getFilename($classname)
68
+ {
69
+ return LIB_DIR . DS . str_replace('_', DS, $classname) . '.php';
70
+ }
71
+
72
+ private static function canLoadClass($classname)
73
+ {
74
+ return file_exists(self::getFilename($classname));
75
+ }
76
+
77
+ /**
78
+ * Creates an instance of a class taking into account classes with the prefix "Custom_" instead of "FACTFinder_".
79
+ * USE THIS method instead of the PHP "new" keyword.
80
+ * Eg. "$obj = new myclass;" should be "$obj = FACTFinder_Loader::getInstance("myclass")" instead!
81
+ * You can also pass arguments for a constructor:
82
+ * FACTFinder_Loader::getInstance('myClass', $arg1, $arg2, ..., $argN)
83
+ *
84
+ * @param string class name to instantiate
85
+ * @param mixed optional as many parameters as the class needs to be created
86
+ * @return object A reference to the object
87
+ */
88
+ public static function getInstance($name)
89
+ {
90
+ if (isset(self::$classNames[$name])) {
91
+ $className = self::$classNames[$name];
92
+ } else {
93
+ $className = self::getClassName($name);
94
+ self::$classNames[$name] = $className;
95
+ }
96
+
97
+ // this snippet is from the typo3 class "t3lib_div" writen by Kasper Skaarhoj <kasperYYYY@typo3.com>
98
+ if (func_num_args() > 1) {
99
+ // getting the constructor arguments by removing this
100
+ // method's first argument (the class name)
101
+ $constructorArguments = func_get_args();
102
+ array_shift($constructorArguments);
103
+
104
+ $reflectedClass = new ReflectionClass($className);
105
+ $instance = $reflectedClass->newInstanceArgs($constructorArguments);
106
+ } else {
107
+ $instance = new $className;
108
+ }
109
+
110
+ return $instance;
111
+ }
112
+
113
+ /**
114
+ * creates an instance of the class once and returns it everytime. uses getInstance
115
+ *
116
+ * @param string class name to instantiate
117
+ * @param mixed optional as many parameters as the class needs to be created
118
+ * @return object A reference to the object
119
+ */
120
+ public static function getSingleton($name)
121
+ {
122
+ if (!isset(self::$singletons[$name])) {
123
+ $params = func_get_args();
124
+ self::$singletons[$name] = call_user_func_array(array("self", "getInstance"), $params);
125
+ }
126
+ return self::$singletons[$name];
127
+ }
128
+
129
+ /**
130
+ * sets the static Logger class from code
131
+ * be aware that only the root loggers configuration will affect how the framework's interna are logged
132
+ *
133
+ * @param string file name of the configuration file
134
+ */
135
+ public static function setLogger(FACTFinder_Logger_LoggerInterface $logger)
136
+ {
137
+ self::$logger = $logger;
138
+ }
139
+
140
+ /**
141
+ * gets a logger. if no logger is specified, the root logger is returned. otherwise, the specified one.
142
+ * this can be configured differently to use it within the shop for example
143
+ *
144
+ * @param string the logger's name
145
+ * @return Logger the specified logger
146
+ */
147
+ public static function getLogger($name = null)
148
+ {
149
+ if (self::$logger == null) {
150
+ self::$logger = new FACTFinder_Logger_BlackHole();
151
+ }
152
+
153
+ return self::$logger;
154
+ }
155
+
156
+ /**
157
+ * check whether there is a custom class with the prefix "FACTFinderCustom_" instead of "FACTFinder_"
158
+ * if non of them exists, it also checks if the name is the classname itselft
159
+ */
160
+ protected static function getClassName($name)
161
+ {
162
+ $name = trim(str_replace('factfinder/', '', $name));
163
+ $name = str_replace(' ', '_', ucwords(str_replace('/', ' ', $name)));
164
+
165
+ // check whether there is a custom or lib-unrelated class
166
+ $oldCustomClassName = 'Custom_' . $name;
167
+ $customClassName = 'FACTFinderCustom_' . $name;
168
+ $factfinderClassName = 'FACTFinder_' . $name;
169
+ $defaultClassName = $name;
170
+
171
+ if (self::canLoadClass($customClassName)) {
172
+ $className = $customClassName;
173
+ } else if (self::canLoadClass($oldCustomClassName)) {
174
+ $className = $oldCustomClassName;
175
+ } else if (self::canLoadClass($factfinderClassName)) {
176
+ $className = $factfinderClassName;
177
+ } else if (class_exists($defaultClassName)) { //trigger other autload methods
178
+ $className = $defaultClassName;
179
+ } else {
180
+ $this->log->error("Could not load class '$defaultClassName'.");
181
+ throw new Exception("class '$defaultClassName' not found");
182
+ }
183
+ return $className;
184
+ }
185
+ }
lib/FACTFinder/Logger/BlackHole.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class FACTFinder_Logger_BlackHole implements FACTFinder_Logger_LoggerInterface
4
+ {
5
+ public function error($error) {}
6
+ public function info($message) {}
7
+ }
lib/FACTFinder/Logger/LoggerInterface.php ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <?php
2
+
3
+ interface FACTFinder_Logger_LoggerInterface {
4
+ public function error($error);
5
+ public function info($message);
6
+ }
lib/FACTFinder/Paging.php ADDED
@@ -0,0 +1,170 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class for creating pagelinks on a search result page. by iterating over an paging object, you will get FACTFinder_Item
5
+ * objects which represent the link for each page, beginning from "getFirtPageNumberShown()" to "getLastPageNumberShown()".
6
+ *
7
+ * @author Rudolf Batt <rb@omikron.net>
8
+ * @version $Id: Paging.php 25893 2010-06-29 08:19:43Z rb $
9
+ * @package FACTFinder\Common
10
+ **/
11
+ class FACTFinder_Paging implements IteratorAggregate
12
+ {
13
+ private $iterator;
14
+ private $currentPage;
15
+ private $pageCount;
16
+ protected $paramsParser;
17
+ protected $params;
18
+ protected $displayPageCount = 9;
19
+
20
+ /**
21
+ * class constructor - puts paging data from the SimpleXMLElement object
22
+ * into usefull structure
23
+ *
24
+ * @param int $currentPage
25
+ * @param int $pageCount
26
+ * @param FACTFinder_ParametersParser $paramsParser because this class is creating its urls
27
+ */
28
+ public function __construct($currentPage, $pageCount, FACTFinder_ParametersParser $paramsParser)
29
+ {
30
+ $this->currentPage = intval($currentPage);
31
+ $this->pageCount = intval($pageCount);
32
+ $this->paramsParser = $paramsParser;
33
+ $this->params = $paramsParser->getRequestParams();
34
+ }
35
+
36
+ /**
37
+ * get iterator to iterate over all paging items around the current page, altogether not more than set
38
+ * by "setDisplayPageCount" (default: 9). each item is an object of FACTFinder_Item
39
+ *
40
+ * @return Traversable
41
+ */
42
+ public function getIterator()
43
+ {
44
+ $iterator = new ArrayIterator();
45
+ for($page = $this->getFirstPageNumberShown(); $page <= $this->getLastPageNumberShown(); $page++) {
46
+ $iterator->append(
47
+ FF::getInstance('item', $page, $this->getPageLink($page), ($page == $this->currentPage))
48
+ );
49
+ }
50
+ return $iterator;
51
+ }
52
+
53
+ /**
54
+ * returns the numer of all existing pages for the current result
55
+ *
56
+ * @return int pagecount
57
+ **/
58
+ public function getPageCount()
59
+ {
60
+ return $this->pageCount;
61
+ }
62
+
63
+ /**
64
+ * returns the current page number
65
+ *
66
+ * @return int pagenumber
67
+ **/
68
+ public function getCurrentPageNumber()
69
+ {
70
+ return $this->currentPage;
71
+ }
72
+
73
+ /**
74
+ * returns the url (link) for the given page. If the page does not exist,
75
+ * it returns an empty string
76
+ *
77
+ * @param int page number
78
+ * @param String optional: link target
79
+ * @return String url (link)
80
+ **/
81
+ public function getPageLink($page_number, $link_target = null)
82
+ {
83
+ if ($page_number > $this->pageCount || $page_number < 1) {
84
+ return '';
85
+ }
86
+ return $this->paramsParser->createPageLink($this->params, array('page' => $page_number), $link_target);
87
+ }
88
+
89
+ /**
90
+ * returns the url (link) for the previous page
91
+ *
92
+ * @param String optional: link target
93
+ * @return String url (link)
94
+ **/
95
+ public function getPreviousPageLink($link_target = '')
96
+ {
97
+ if ( $this->currentPage > 1) {
98
+ $previous_page_number = ($this->currentPage - 1);
99
+ } else {
100
+ return '';
101
+ }
102
+ return $this->getPageLink($previous_page_number, $link_target);
103
+ }
104
+
105
+ /**
106
+ * returns the url (link) for the next page
107
+ *
108
+ * @param String optional: link target
109
+ * @return String url (link)
110
+ **/
111
+ public function getNextPageLink($link_target = '')
112
+ {
113
+ if ( $this->currentPage < $this->pageCount) {
114
+ $previous_page_number = ($this->currentPage + 1);
115
+ } else {
116
+ return '';
117
+ }
118
+ return $this->getPageLink($previous_page_number, $link_target);
119
+ }
120
+
121
+ /**
122
+ * set maximum count of pages to display
123
+ *
124
+ * @param int count of pages to display
125
+ * @return void
126
+ */
127
+ public function setDisplayPageCount($displayPageCount)
128
+ {
129
+ $this->displayPageCount = intval($displayPageCount);
130
+ }
131
+
132
+ /**
133
+ * returns the first page number for the pagelinks to be shown
134
+ * needs the number of the maximum shown links
135
+ *
136
+ * @param int page links count
137
+ * @return int first shown page number
138
+ **/
139
+ public function getFirstPageNumberShown()
140
+ {
141
+ if ($this->currentPage <= floor($this->displayPageCount / 2) || $this->pageCount < $this->displayPageCount) {
142
+ return 1;
143
+ } else if ($this->currentPage > ($this->pageCount - $this->displayPageCount +1 )) {
144
+ return ($this->pageCount - $this->displayPageCount + 1);
145
+ } else {
146
+ return ($this->currentPage - floor($this->displayPageCount / 2));
147
+ }
148
+ }
149
+
150
+ /**
151
+ * returns the last page number for the pagelinks to be shown
152
+ * needs the number of the maximum shown links
153
+ *
154
+ * @param int page links count
155
+ * @return int first shown page number
156
+ **/
157
+ public function getLastPageNumberShown()
158
+ {
159
+ if ($this->pageCount < $this->displayPageCount) {
160
+ return $this->pageCount;
161
+ }
162
+
163
+ $first_page_number = $this->getFirstPageNumberShown($this->displayPageCount);
164
+ if ($first_page_number+$this->displayPageCount >= $this->pageCount) {
165
+ return $this->pageCount;
166
+ } else {
167
+ return $first_page_number+$this->displayPageCount;
168
+ }
169
+ }
170
+ }
lib/FACTFinder/Parameters.php ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * the factfinder parameters contains all relevant parameter which makes effect to the factfinder search result.
5
+ * It does NOT contain all request parameters. The parameters represents a state of a factfinder result.
6
+ *
7
+ * @author Rudolf Batt <rb@omikron.net>
8
+ * @version $Id: Parameters.php 25893 2010-06-29 08:19:43Z rb $
9
+ * @package FACTFinder\Common
10
+ */
11
+ class FACTFinder_Parameters
12
+ {
13
+ private $query;
14
+ private $channel;
15
+ private $productsPerPage;
16
+ private $page;
17
+ private $filters;
18
+ private $sortings;
19
+ private $isNavigation;
20
+ private $followSearch;
21
+
22
+ /**
23
+ * @param string query
24
+ * @param string channel
25
+ * @param int productsPerPage
26
+ * @param int page
27
+ * @param array filters
28
+ * @param array sortings
29
+ * @param boolean isNavigation
30
+ * @param int followSearch
31
+ */
32
+ public function __construct($query, $channel, $productsPerPage = null, $page = 1, array $filters = array(), array $sortings = array(), $isNavigation = false, $followSearch = 10000) {
33
+ $this->query = strval($query);
34
+ $this->channel = strval($channel);
35
+ $this->productsPerPage = $productsPerPage == null ? null : intval($productsPerPage);
36
+ $this->page = intval($page);
37
+ $this->filters = $filters;
38
+ $this->sortings = $sortings;
39
+ $this->isNavigation = $isNavigation == true;
40
+ $this->followSearch = intval($followSearch);
41
+ }
42
+
43
+ /**
44
+ * @return string
45
+ */
46
+ public function getQuery()
47
+ {
48
+ return $this->query;
49
+ }
50
+
51
+ /**
52
+ * @return string
53
+ */
54
+ public function getChannel()
55
+ {
56
+ return $this->channel;
57
+ }
58
+
59
+ /**
60
+ * @return int
61
+ */
62
+ public function getProductsPerPage()
63
+ {
64
+ return $this->productsPerPage;
65
+ }
66
+
67
+ /**
68
+ * @return int
69
+ */
70
+ public function getPage()
71
+ {
72
+ return $this->page;
73
+ }
74
+
75
+ /**
76
+ * @return array string => string
77
+ */
78
+ public function getFilters()
79
+ {
80
+ return $this->filters;
81
+ }
82
+
83
+ /**
84
+ * @return array string => string
85
+ */
86
+ public function getSortings()
87
+ {
88
+ return $this->sortings;
89
+ }
90
+
91
+ /**
92
+ * @return boolean true if navigation is enabled
93
+ */
94
+ public function isNavigation()
95
+ {
96
+ return $this->isNavigation;
97
+ }
98
+
99
+ /**
100
+ * @return int follow search value
101
+ */
102
+ public function getFollowSearch()
103
+ {
104
+ return $this->followSearch;
105
+ }
106
+ }
lib/FACTFinder/ParametersParser.php ADDED
@@ -0,0 +1,372 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * contains the FACTFinder_ParametersParser class
4
+ *
5
+ * @author Rudolf Batt <rb@omikron.net>
6
+ * @version $Id: ParametersParser.php 25893 2010-06-29 08:19:43Z rb $
7
+ * @package FACTFinder\Common
8
+ */
9
+
10
+ /**
11
+ * this class handles the parameters conversion between the client url, the links on the webpage and the url for the
12
+ * server. it can be seen as a parameter factory.
13
+ */
14
+ class FACTFinder_ParametersParser
15
+ {
16
+ private static $w283751Done = false;
17
+ private $requestParams;
18
+ private $requestTarget;
19
+
20
+ protected $config;
21
+ protected $encodingHandler;
22
+
23
+ protected $log;
24
+
25
+ /**
26
+ * @param FACTFinder_Abstract_IConfiguration config
27
+ * @param FACTFinder_EncodingHandler $encodingHandler
28
+ */
29
+ public function __construct(FACTFinder_Abstract_Configuration $config, FACTFinder_EncodingHandler $encodingHandler)
30
+ {
31
+ $this->log = FF::getLogger();
32
+ $this->config = $config;
33
+ $this->encodingHandler = $encodingHandler;
34
+ }
35
+
36
+ /**
37
+ * DEPRECATED, because it also might destroy other components of the system which rely on the standard PHP. For example this
38
+ * method don't manage array-parameters e.g. "foo[0]=bar" like expected.
39
+ * This method is not in internal use any more
40
+ *
41
+ * runs a workaround for php to restore the original parameter names from the url respectively $_SERVER['QUERY_STRING'].
42
+ * this method will only run once and change the global variables $GLOBALS, $_GET and $_REQUEST. parameters which are
43
+ * transformed by php will be left at the $_REQUEST array, the $_GET array will only contain the correct parameters
44
+ *
45
+ * @link http://stackoverflow.com/questions/283751/php-replaces-spaces-with-underlines
46
+ * @deprecated and not in interal use any more
47
+ * @return void
48
+ */
49
+ final public static function runWorkaround283751()
50
+ {
51
+ if (self::$w283751Done === false && isset($_SERVER['QUERY_STRING'])) {
52
+ $params = self::parseParamsFromString($_SERVER['QUERY_STRING']);
53
+ $_GET = array();
54
+ $_GLOBALS['_GET'] = $_GET;
55
+ foreach($params AS $key => $value){
56
+ $_GET[$key] = $value;
57
+ $_REQUEST[$key] = $value;
58
+ $GLOBALS['_GET'][$key] = $value;
59
+ $GLOBALS['_REQUEST'][$key] = $value;
60
+ }
61
+ self::$w283751Done = true;
62
+ }
63
+ }
64
+
65
+ /**
66
+ * loads the parameters from request and returns them as string-to-string array
67
+ * also considers the mapping and ignore rules
68
+ *
69
+ * @return array of params
70
+ */
71
+ public function getRequestParams()
72
+ {
73
+ if ($this->requestParams == null) {
74
+ if (isset($_SERVER['QUERY_STRING'])) {
75
+ $requestParams = array_merge($_POST, self::parseParamsFromString($_SERVER['QUERY_STRING']));
76
+ } else if (isset($_GET)) {
77
+ $requestParams = array_merge($_POST, $_GET); // dont use $_REQUEST, because it also contains $_COOKIE;
78
+ } else {
79
+ // for cli
80
+ $requestParams = array();
81
+ }
82
+
83
+ $this->requestParams = $this->encodingHandler->encodeUrlForPage($requestParams);
84
+ }
85
+ return $this->requestParams;
86
+ }
87
+
88
+ /**
89
+ * @param array parameters. if null, using the request parameters (default: null)
90
+ * @return FACTFinder_Parameters object
91
+ */
92
+ public function getFactfinderParams(array $params = null)
93
+ {
94
+ if ($params == null) {
95
+ $params = $this->getServerRequestParams();
96
+ $params = $this->encodingHandler->encodeServerUrlForPageUrl($params);
97
+ }
98
+
99
+ $filters = array();
100
+ $sortings = array();
101
+ foreach($params AS $key => $value) {
102
+ if (strpos($key, 'filter') === 0) {
103
+ $filters[str_replace('filter', '', $key)] = $value;
104
+ } else
105
+ if (strpos($key, 'sort' && ($value == 'asc' || $value == 'desc')) === 0) {
106
+ $sortings[str_replace('sort', '', $key)] = $value;
107
+ }
108
+ }
109
+
110
+ return FF::getInstance('parameters',
111
+ isset($params['query']) ? $params['query'] : '',
112
+ $this->config->getChannel(),
113
+ isset($params['productsPerPage']) ? $params['productsPerPage'] : null,
114
+ isset($params['page']) ? $params['page'] : 1,
115
+ $filters,
116
+ $sortings,
117
+ (isset($params['catalog']) && $params['catalog'] == 'true'),
118
+ isset($params['followSearch']) ? $params['followSearch'] : 10000
119
+ );
120
+ }
121
+
122
+ /**
123
+ * @param String parameters
124
+ * @return FACTFinder_Parameters object
125
+ */
126
+ public function getFactfinderParamsFromString($paramString)
127
+ {
128
+ $params = self::parseParamsFromString($paramString);
129
+ return $this->getFactfinderParams($params);
130
+ }
131
+
132
+ /**
133
+ * converts the factfinder parameters object into a params array
134
+ *
135
+ * @return array params
136
+ */
137
+ public function parseFactfinderParams(FACTFinder_Parameters $ffparams)
138
+ {
139
+ $filters = array();
140
+ foreach($ffparams->getFilters() AS $key => $value) {
141
+ $filters['filter'.$key] = $value;
142
+ }
143
+
144
+ $sortings = array();
145
+ foreach($ffparams->getSortings() AS $key => $value) {
146
+ $sortings['sort'.$key] = $value;
147
+ }
148
+
149
+ return array_merge(
150
+ array(
151
+ 'query' => $ffparams->getQuery(),
152
+ 'channel' => $ffparams->getChannel(),
153
+ 'productsPerPage' => $ffparams->getProductsPerPage(),
154
+ 'page' => $ffparams->getPage(),
155
+ 'followSearch' => $ffparams->getFollowSearch()
156
+ ),
157
+ $filters,
158
+ $sortings
159
+ );
160
+ }
161
+
162
+ /**
163
+ * extracts a parameter array with name=>value pairs from an url string.
164
+ * also only url encoding is done but no further encodings.
165
+ * this method does not handle array variables such like "foo[0]=bar"
166
+ *
167
+ * @param string url
168
+ * @return array of parameter variables
169
+ */
170
+ public static function parseParamsFromString($paramString)
171
+ {
172
+ if (strpos($paramString, '?') !== false) {
173
+ $paramString = substr($paramString, strpos($paramString, '?')+1);
174
+ }
175
+ $paramsArray = array();
176
+ $a_pairs = explode('&', $paramString);
177
+ foreach($a_pairs AS $s_pair){
178
+ $a_pair = explode('=', $s_pair);
179
+ if(empty($a_pair[0])) continue;
180
+ if(count($a_pair) == 1 || empty($a_pair[1])) $a_pair[1] = '';
181
+
182
+ $a_pair[0] = urldecode($a_pair[0]);
183
+ $a_pair[1] = urldecode($a_pair[1]);
184
+
185
+ $paramsArray[$a_pair[0]] = $a_pair[1];
186
+ }
187
+ return $paramsArray;
188
+ }
189
+
190
+ /**
191
+ * the FACT-Finder result is UTF-8 encoded, so this method parses a url string from the request and also does
192
+ * utf-decoding if needed
193
+ *
194
+ * @param string from factfinder result
195
+ * @return array of paramter variables
196
+ */
197
+ public function parseParamsFromResultString($paramString)
198
+ {
199
+ $params = self::parseParamsFromString($paramString);
200
+ $params = $this->encodingHandler->encodeServerUrlForPageUrl($params);
201
+ return $params;
202
+ }
203
+
204
+ /**
205
+ * get a single value from the request or the default value, if this value does not exist
206
+ *
207
+ * @param parameter name
208
+ * @param default value (default: null)
209
+ * @return request value of parameter $name or $defaultValue if parameter does not exist
210
+ */
211
+ public function getRequestParam($name, $defaultValue = null)
212
+ {
213
+ $params = $this->getRequestParams();
214
+ return isset($params[$name]) ? trim($params[$name]) : $defaultValue;
215
+ }
216
+
217
+ /**
218
+ * returns the params array but with the server mappings and removed ignored server parameters . if params array is
219
+ * not set, the request params will be used
220
+ *
221
+ * @param array parameters (optional)
222
+ * @return array parameters without ignored parameters
223
+ */
224
+ public function getServerRequestParams(array $params = null) {
225
+ if ($params == null) {
226
+ $params = $this->getRequestParams();
227
+ }
228
+
229
+ $params = $this->doServerMappings($params);
230
+ $params = $this->removeIgnoredParams($params, $this->config->getIgnoredServerParams());
231
+ $params = $this->addRequiredParams($params, $this->config->getRequiredServerParams());
232
+ $params = $this->encodingHandler->encodeForServerUrl($params);
233
+
234
+ return $params;
235
+ }
236
+
237
+ /**
238
+ * creates the link-url for the webpage (no html code!). see {@link http://de3.php.net/manual/en/function.array-merge.php array_merge}
239
+ * and {@link http://de3.php.net/manual/en/function.http-build-query.php http_build_query} to know, how the two arrays
240
+ * are merged and how the link will be constructed. additionaly this method will remove parameters which are configured
241
+ * to be ignored
242
+ *
243
+ * @param array of parameters
244
+ * @param array (optional) additional parameters which will overwrite the first parameters if a same key is used
245
+ * @param string (optional) string which will be prepended to the link. if none is given, getRequestTarget() is used
246
+ * @return url for a page link
247
+ */
248
+ public function createPageLink(array $params, array $addParams = array(), $target = null)
249
+ {
250
+ if ($target == null) {
251
+ $target = $this->getRequestTarget();
252
+ }
253
+
254
+ $linkParams = array_merge($params, $addParams);
255
+
256
+ $linkParams = $this->doPageMappings($linkParams);
257
+ $linkParams = $this->removeIgnoredParams($linkParams, $this->config->getIgnoredPageParams());
258
+ $linkParams = $this->addRequiredParams($linkParams, $this->config->getRequiredPageParams());
259
+
260
+ return $target.'?'.http_build_query($linkParams, '', '&');
261
+ }
262
+
263
+ /**
264
+ * remove the ignored params from the params array if set
265
+ *
266
+ * @param array params
267
+ * @param array ignored params, where the param names are the array-keys
268
+ * @return array new modified params
269
+ */
270
+ private function removeIgnoredParams($params, $ignoredParams)
271
+ {
272
+ $returnParams = array();
273
+ foreach($params as $key => $value) {
274
+ // copy each param and do not set to null, because mappings are stored as references in the params array
275
+ if(!isset($ignoredParams[$key]) && !empty($value)) {
276
+ $returnParams[$key] = $value;
277
+ }
278
+ }
279
+ return $returnParams;
280
+ }
281
+
282
+ /**
283
+ * adds the params from the required params map to the params array if not already set
284
+ *
285
+ * @param array params
286
+ * @param array required params as string to string map (array-key = paramname; array-value = default param value)
287
+ * @return array new modified params
288
+ */
289
+ private function addRequiredParams($params, $requiredParams)
290
+ {
291
+ $requestParams = $this->getRequestParams();
292
+ foreach($requiredParams AS $paramName => $defaultValue) {
293
+ if (!isset($params[$paramName])) {
294
+ $params[$paramName] = isset($requestParams[$paramName]) ? $requestParams[$paramName] : $defaultValue;
295
+ }
296
+ }
297
+ return $params;
298
+ }
299
+
300
+ /**
301
+ * get target of the current request url, from "$_SERVER['REQUEST_URI']".
302
+ *
303
+ * @return string request target
304
+ */
305
+ protected function getRequestTarget()
306
+ {
307
+ if ($this->requestTarget == null) {
308
+ // workaround for some servers (IIS) which do not provide '$_SERVER['REQUEST_URI']'
309
+ if (!isset($_SERVER['REQUEST_URI'])) {
310
+ $arr = explode("/", $_SERVER['PHP_SELF']);
311
+ $_SERVER['REQUEST_URI'] = "/" . $arr[count($arr)-1];
312
+ if (isset($_SERVER['argv'][0]) && $_SERVER['argv'][0]) {
313
+ $_SERVER['REQUEST_URI'] .= "?" . $_SERVER['argv'][0];
314
+ }
315
+ }
316
+
317
+ if (strpos($_SERVER['REQUEST_URI'], '?') === false) {
318
+ $this->requestTarget = $_SERVER['REQUEST_URI'];
319
+ } else {
320
+ $this->requestTarget = substr($_SERVER['REQUEST_URI'], 0, strpos($_SERVER['REQUEST_URI'], '?'));
321
+ }
322
+ }
323
+ return $this->requestTarget;
324
+ }
325
+
326
+ /**
327
+ * do mapping for a params array with the page mapping settings from the config. so this method expects server params
328
+ * and return params for the page
329
+ *
330
+ * @param array paramters
331
+ * @return array mapped parameters
332
+ */
333
+ private function doPageMappings(array $params)
334
+ {
335
+ return $this->doMapping($params, $this->config->getPageMappings());
336
+ }
337
+
338
+ /**
339
+ * do mapping for a params array with the server mapping settings from the config. so this method expects page params
340
+ * and return params for the server
341
+ *
342
+ * @param array paramters
343
+ * @return array mapped parameters
344
+ */
345
+ private function doServerMappings(array $params)
346
+ {
347
+ return $this->doMapping($params, $this->config->getServerMappings());
348
+ }
349
+
350
+ /**
351
+ * maps the keys in the array using the rules. if a "from" parameter does not exist, but the according "to" parameter
352
+ * exist, the "from" will be create - so this mapping normaly works for both directions
353
+ *
354
+ * @param array paramters
355
+ * @param mixed iterable mapping rules
356
+ * @return array mapped parameters
357
+ */
358
+ private function doMapping(array $params, array $mappingRules)
359
+ {
360
+ foreach($mappingRules AS $from => $to) {
361
+ if (isset($params[$from])) { //"from" is more important..
362
+ $params[$to] = &$params[$from];
363
+ } else if (isset($params[$to])) { //but if it does not exist but "to" exists, then "create" from
364
+ $params[$from] = &$params[$to];
365
+ } else { //if none of them exists, just create the params with a null value
366
+ $params[$from] = null;
367
+ $params[$to] = &$params[$from];
368
+ }
369
+ }
370
+ return $params;
371
+ }
372
+ }
lib/FACTFinder/ProductsPerPageOptions.php ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * represents the fact-finder product-per-page-options. by iterating over an FACTFinder_ProductsPerPageOptions
5
+ * object, you will get FACTFinder_Item objects, where each represents one products-per-page option.
6
+ *
7
+ * @author Rudolf Batt <rb@omikron.net>
8
+ * @version $Id: ProductsPerPageOptions.php 25893 2010-06-29 08:19:43Z rb $
9
+ * @package FACTFinder\Common
10
+ **/
11
+ class FACTFinder_ProductsPerPageOptions implements IteratorAggregate
12
+ {
13
+ private $options;
14
+ private $selectedOption = null;
15
+ private $defaultOption = null;
16
+
17
+ /**
18
+ * @param array int to string map; the integer is product-per-page option and the string is the according url
19
+ * @param int default option (default: first option)
20
+ * @param int selected option (default: default option)
21
+ */
22
+ public function __construct(array $options, $defaultOption = -1, $selectedOption = -1) {
23
+ $defaultOption = intval($defaultOption);
24
+ $selectedOption = intval($selectedOption);
25
+
26
+ $this->options = new ArrayIterator();
27
+ foreach($options AS $option => $url) {
28
+ $item = FF::getInstance('item', intval($option), $url, ($option == $selectedOption));
29
+ if ($option == $selectedOption) {
30
+ $this->selectedOption = $item;
31
+ }
32
+ if ($option == $defaultOption) {
33
+ $this->defaultOption = $item;
34
+ }
35
+ $this->options->append($item);
36
+ }
37
+
38
+ if ($this->defaultOption == null && $this->options->count() > 0) {
39
+ $this->defaultOption = $this->options[0];
40
+ }
41
+ if ($this->selectedOption == null && $this->defaultOption != null) {
42
+ $this->selectedOption = $this->defaultOption;
43
+ }
44
+ }
45
+
46
+ /**
47
+ * get iterator to iterate over all products-per-page-options. each item is an object of FACTFinder_Item
48
+ *
49
+ * @return Traversable
50
+ */
51
+ public function getIterator()
52
+ {
53
+ return $this->options;
54
+ }
55
+
56
+ /**
57
+ * @return FACTFinder_Item default products per page option
58
+ */
59
+ public function getDefaultOption()
60
+ {
61
+ return $this->defaultOption;
62
+ }
63
+
64
+ /**
65
+ * @param FACTFinder_Item
66
+ * @return boolean true, if the set object is the default product-per-page-option
67
+ */
68
+ public function isDefaultOption(FACTFinder_Item $option) {
69
+ return $this->defaultOption->getValue() == $option->getValue();
70
+ }
71
+
72
+ /**
73
+ * @return FACTFinder_Item selected products per page option
74
+ */
75
+ public function getSelectedOption()
76
+ {
77
+ return $this->selectedOption;
78
+ }
79
+ }
lib/FACTFinder/Record.php ADDED
@@ -0,0 +1,251 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * represents a FACT-Finder data record
5
+ *
6
+ * @author Rudolf Batt <rb@omikron.net>
7
+ * @version $Id: Record.php 25893 2010-06-29 08:19:43Z rb $
8
+ * @package FACTFinder\Common
9
+ **/
10
+ class FACTFinder_Record
11
+ {
12
+ protected $id;
13
+ protected $similarity;
14
+ protected $position;
15
+ protected $origPosition;
16
+ protected $fieldValues;
17
+ protected $fieldNames;
18
+
19
+ /**
20
+ * new values since FACT-Finder 6.6
21
+ */
22
+ protected $seoPath = '';
23
+ protected $keywords = array();
24
+
25
+ /**
26
+ * class constructor - creates a record using the given values. if the array contains fieldnames as array-keys, they
27
+ * could be used to get the values again
28
+ *
29
+ * @param string id
30
+ * @param double similarity
31
+ * @param int originalPosition (optional)
32
+ * @param array fieldValues (optional)
33
+ **/
34
+ public function __construct($id, $similarity = 100, $position = 0, $origPosition = 0, array $fieldValues = null)
35
+ {
36
+ $this->id = trim($id);
37
+ $this->similarity = doubleval($similarity);
38
+ if ($this->similarity > 100.0) {
39
+ $this->similarity = 100.0;
40
+ } else if ($this->similarity < 0.0) {
41
+ $this->similarity = 0.0;
42
+ }
43
+
44
+ $this->position = intval($position);
45
+ $this->origPosition = intval($origPosition);
46
+
47
+ if (empty($fieldValues)) {
48
+ $this->fieldNames = array();
49
+ $this->fieldValues = array();
50
+ } else {
51
+ $this->setValues($fieldValues);
52
+ }
53
+ }
54
+
55
+ /**
56
+ * @return string id
57
+ */
58
+ public function getId()
59
+ {
60
+ return $this->id;
61
+ }
62
+
63
+ /**
64
+ * get FACT-Finder similarity, which lays between 0.0 and 100.0, but normaly is greater then the set minSimilarity
65
+ *
66
+ * @return double similarity
67
+ */
68
+ public function getSimilarity()
69
+ {
70
+ return $this->similarity;
71
+ }
72
+
73
+ /**
74
+ * get original position or 0 if there is no original position
75
+ *
76
+ * @return int original position
77
+ */
78
+ public function getOriginalPosition()
79
+ {
80
+ return $this->origPosition;
81
+ }
82
+
83
+ /**
84
+ * get position or 0 if there is no position
85
+ *
86
+ * @return int position
87
+ */
88
+ public function getPosition()
89
+ {
90
+ return $this->position;
91
+ }
92
+
93
+ /**
94
+ * get array of keywords for this record. this keywords can be used as meta-keywords on the website
95
+ * for seo-optimization.
96
+ * by default (if used with an older FF-version or when the seo features are not enabled) the keywords are an empty array
97
+ *
98
+ * @version since FF6.6
99
+ * @return array
100
+ */
101
+ public function getKeywords()
102
+ {
103
+ return $this->keywords;
104
+ }
105
+
106
+ /**
107
+ * returnes the seo path which can be used to fetch the data from this record from FACT-Finder.
108
+ * this can be used as link to the detail page of this product.
109
+ * by default (if used with an older FF-version or when the seo features are not enabled) this path is an empty string
110
+ *
111
+ * @version since FF6.6
112
+ * @return string seoPath to this record
113
+ */
114
+ public function getSeoPath()
115
+ {
116
+ return $this->seoPath;
117
+ }
118
+
119
+ /**
120
+ * get a value from a field defined by the argument $field, which can be a fieldnumber or a fieldname
121
+ * of the field does not exist, null will be returned
122
+ *
123
+ * @throws Exception if the argument $field is either an integer nor a string
124
+ * @param int|string fieldnumber or fieldname
125
+ * @return string fieldvalue or null if field does not exist
126
+ */
127
+ public function getValue($field)
128
+ {
129
+ $returnValue = null;
130
+ if (is_int($field)) {
131
+ $returnValue = isset($this->fieldValues[$field]) ? $this->fieldValues[$field] : null;
132
+ } else if (is_string($field)) {
133
+ //get value by number and the number by name (mapping from name to value)
134
+ $returnValue = isset($this->fieldNames[$field]) ? $this->fieldValues[$this->fieldNames[$field]] : null;
135
+ }
136
+ return $returnValue;
137
+ }
138
+
139
+ /**
140
+ * proxy method for getValue()
141
+ * @see FACTFinder_Record::getValue()
142
+ */
143
+ public function __get($name)
144
+ {
145
+ return $this->getValue($name);
146
+ }
147
+
148
+ /**
149
+ * set seo path for this record. this seo path can't be set by the constructor, because it was added
150
+ * in a later version.
151
+ *
152
+ * @version since FF6.6
153
+ * @param string seo path
154
+ */
155
+ public function setSeoPath($seoPath)
156
+ {
157
+ if ($seoPath != null) {
158
+ $this->seoPath = strval($seoPath);
159
+ }
160
+ }
161
+
162
+ /**
163
+ * add keyword to this record.
164
+ *
165
+ * @version since FF6.6
166
+ * @see FACTFinder_Record::getKeywords()
167
+ * @param string keyword
168
+ */
169
+ public function addKeyword($keyword) {
170
+ $this->keywords[] = $keyword;
171
+ }
172
+
173
+ /**
174
+ * add keywords to this record.
175
+ * the keys of the array are ignored, so only the values are used to set the keywords.
176
+ *
177
+ * @version since FF6.6
178
+ * @see FACTFinder_Record::getKeywords()
179
+ * @param array of strings/keywords
180
+ */
181
+ public function addKeywords(array $keywords) {
182
+ $this->keywords += array_values($keywords);
183
+ }
184
+
185
+ /**
186
+ * set keywords for this record.
187
+ * the keys of the array are ignored, so only the values are used to set the keywords.
188
+ *
189
+ * @version since FF6.6
190
+ * @see FACTFinder_Record::getKeywords()
191
+ * @param array of strings/keywords
192
+ */
193
+ public function setKeywords(array $keywords)
194
+ {
195
+ $this->keywords = array_values($keywords);
196
+ }
197
+
198
+ /**
199
+ * set a value to field defined by the argument $field, which can be a fieldnumber or a fieldname
200
+ *
201
+ * @throws Exception if the argument $field is neither an integer nor a string
202
+ * @param int|string fieldnumber or fieldname
203
+ * @param string fieldvalue
204
+ * @return void
205
+ */
206
+ public function setValue($field, $value)
207
+ {
208
+ if (is_int($field)) {
209
+ $this->fieldValues[$field] = $value;
210
+ } else if (is_string($field)) {
211
+ if (!isset($this->fieldNames[$field])) {
212
+ // create a new field
213
+ $this->fieldNames[$field] = sizeof($this->fieldValues);
214
+ $this->fieldValues[] = $value;
215
+ } else {
216
+ $this->fieldValues[$this->fieldNames[$field]] = $value;
217
+ }
218
+ } else {
219
+ $this->log->error("Could not refer to a field using ".gettype($field));
220
+ throw new Exception("it is not (yet) possible to refer to a field using ".gettype($field));
221
+ }
222
+ }
223
+
224
+ /**
225
+ * proxy method for setValue()
226
+ * @see FACTFinder_Record::setValue()
227
+ *
228
+ * @throws Exception if the argument $field is either an integer nor a string
229
+ * @param int|string fieldnumber or fieldname
230
+ * @param string fieldvalue
231
+ * @return void
232
+ */
233
+ public function __set($name, $value)
234
+ {
235
+ return $this->setValue($name, $value);
236
+ }
237
+
238
+ /**
239
+ * set a bulk of values. if the array contains fieldnames as array-keys, they
240
+ * could be used to get the values again
241
+ *
242
+ * @param array fieldvalues with fieldnames as key
243
+ * @return void
244
+ */
245
+ public function setValues(array $fieldValues)
246
+ {
247
+ foreach ($fieldValues AS $name => $value) {
248
+ $this->setValue($name, $value);
249
+ }
250
+ }
251
+ }
lib/FACTFinder/Result.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * this class represents a fact-finder search result. By iterating over a result object, you will get
5
+ * FACTFinder_Record objects in the loop.
6
+ *
7
+ * @author Rudolf Batt <rb@omikron.net>
8
+ * @version $Id: Result.php 25893 2010-06-29 08:19:43Z rb $
9
+ * @category Collection
10
+ * @package FACTFinder\Common
11
+ */
12
+ class FACTFinder_Result extends ArrayIterator
13
+ {
14
+ private $foundRecordsCount;
15
+
16
+ /**
17
+ * @param array record (default: empty array)
18
+ * @param int number of records factfinder found for the according query (default: 0)
19
+ */
20
+ public function __construct(array $records = array(), $foundRecordsCount = 0){
21
+ parent::__construct($records);
22
+ $this->foundRecordsCount = intval($foundRecordsCount);
23
+ }
24
+
25
+ /**
26
+ * return number of records found in the whole FACT-Finder result.
27
+ * this object only contains the records for the current page, that must not be the same count
28
+ *
29
+ * @return int found records count
30
+ */
31
+ public function getFoundRecordsCount(){
32
+ return $this->foundRecordsCount;
33
+ }
34
+ }
lib/FACTFinder/SingleWordSearchItem.php ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * represents a suggest single word search item with a preview of the found products for this query
5
+ *
6
+ * @author Rudolf Batt <rb@omikron.net>
7
+ * @version $Id: SingleWordSearchItem.php 25893 2010-06-29 08:19:43Z rb $
8
+ * @package FACTFinder\Common
9
+ */
10
+ class FACTFinder_SingleWordSearchItem extends FACTFinder_SuggestQuery
11
+ {
12
+ private $previewRecords = array();
13
+
14
+ /**
15
+ * @param array of FACTFinder_Record objects
16
+ * @return void
17
+ */
18
+ public function addPreviewRecords(array $previewRecords)
19
+ {
20
+ $this->previewRecords += $previewRecords;
21
+ }
22
+
23
+ /**
24
+ * @param FACTFinder_Record object
25
+ * @return void
26
+ */
27
+ public function addPreviewRecord(FACTFinder_Record $record)
28
+ {
29
+ $this->previewRecords[] = $record;
30
+ }
31
+
32
+ /**
33
+ * @return array of FACTFinder_Record objects or empty array if there are no preview objects
34
+ */
35
+ public function getPreviewRecords()
36
+ {
37
+ return $this->previewRecords;
38
+ }
39
+ }
lib/FACTFinder/SuggestQuery.php ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * represents a query for suggest
5
+ *
6
+ * @author Rudolf Batt <rb@omikron.net>
7
+ * @version $Id: SuggestQuery.php 25893 2010-06-29 08:19:43Z rb $
8
+ * @package FACTFinder\Common
9
+ */
10
+ class FACTFinder_SuggestQuery
11
+ {
12
+ private $query;
13
+ private $url;
14
+ private $hitCount;
15
+ private $type;
16
+ private $imageUrl;
17
+
18
+ /**
19
+ * @param string $value query
20
+ * @param string $url url which uses the suggested query
21
+ * @param string $hitCount number of products, which will be found with this query
22
+ * @param string $type type of the query
23
+ * @param string imageUrl
24
+ */
25
+ public function __construct($query, $url, $hitCount = '', $type = '', $imageUrl = '') {
26
+ $this->query = strval($query);
27
+ $this->url = strval($url);
28
+ $this->hitCount = $hitCount;
29
+ $this->type = $type;
30
+ $this->imageUrl = $imageUrl;
31
+ }
32
+
33
+ /**
34
+ * @return string
35
+ */
36
+ public function getQuery() {
37
+ return $this->query;
38
+ }
39
+
40
+ /**
41
+ * @return string
42
+ */
43
+ public function getUrl() {
44
+ return $this->url;
45
+ }
46
+
47
+ /**
48
+ * return int how many products will be found by this query
49
+ */
50
+ public function getHitCount() {
51
+ return $this->hitCount;
52
+ }
53
+
54
+ /**
55
+ * simple string which describes where this suggest query comes from (i.e. productname, category, logfile)
56
+ *
57
+ * @return string
58
+ */
59
+ public function getType() {
60
+ return $this->type;
61
+ }
62
+
63
+ /**
64
+ * return image url, if one exists, otherwise returns empty string
65
+ *
66
+ * @return string
67
+ */
68
+ public function getImageUrl() {
69
+ return $this->imageUrl;
70
+ }
71
+ }
lib/FACTFinder/TagQuery.php ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * represents a tag item for the tagcloud
5
+ *
6
+ * @author Rudolf Batt <rb@omikron.net>
7
+ * @version $Id: TagQuery.php 25893 2010-06-29 08:19:43Z rb $
8
+ * @package FACTFinder\Common
9
+ */
10
+ class FACTFinder_TagQuery extends FACTFinder_Item
11
+ {
12
+ private $weight;
13
+ private $searchCount;
14
+
15
+ /**
16
+ * @param string $value query
17
+ * @param string $url
18
+ * @param boolean true if this tag lead to the current search result
19
+ * @param double $weight value between 0.0 and 1.0 (optional - default 0.0)
20
+ * @param int $searchCount how often this query was searched in the last 7 days (optional - default 0)
21
+ */
22
+ public function __construct($value, $url, $isSelected = false, $weight = 0.0, $searchCount = 0) {
23
+ parent::__construct($value, $url, $isSelected);
24
+ $this->weight = floatval($weight);
25
+ $this->searchCount = intval($searchCount);
26
+ }
27
+
28
+ /**
29
+ * @return double value between 0.0 and 1.0 to calculate the importance of the query
30
+ */
31
+ public function getWeight() {
32
+ return $this->weight;
33
+ }
34
+
35
+ /**
36
+ * @return int how often this query was searched in the last 7 days
37
+ */
38
+ public function getSearchCount() {
39
+ return $this->searchCount;
40
+ }
41
+ }
lib/FACTFinder/Util.php ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * util class for some repeated issues which do not fit to a single class
5
+ *
6
+ * @author Rudolf Batt <rb@omikron.net>
7
+ * @version $Id: Util.php 25893 2010-06-29 08:19:43Z rb $
8
+ * @package FACTFinder\Common
9
+ **/
10
+ class FACTFinder_Util
11
+ {
12
+ protected $searchAdapter;
13
+ protected $ffparams;
14
+
15
+ public function __construct(FACTFinder_Parameters $ffparams, FACTFinder_Abstract_SearchAdapter $searchAdapter) {
16
+ $this->ffparams = $ffparams;
17
+ $this->searchAdapter = $searchAdapter;
18
+ }
19
+
20
+ /**
21
+ * @return string javascript method call "clickProduct" with all needed arguments
22
+ */
23
+ public function createJavaScriptClickCode($record, $title, $sid)
24
+ {
25
+ $query = addcslashes(htmlspecialchars($this->ffparams->getQuery()), "'");
26
+ $channel = $this->ffparams->getChannel();
27
+
28
+ $currentPageNumber = $this->searchAdapter->getPaging()->getCurrentPageNumber();
29
+ $origPageSize = $this->searchAdapter->getProductsPerPageOptions()->getDefaultOption()->getValue();
30
+ $pageSize = $this->searchAdapter->getProductsPerPageOptions()->getSelectedOption()->getValue();
31
+
32
+ $position = $record->getPosition();
33
+ if ($position != 0) {
34
+ $originalPosition = $record->getOriginalPosition();
35
+ $similarity = $record->getSimilarity();
36
+ $id = $record->getId();
37
+
38
+ $title = addslashes($title);
39
+ $sid = addslashes($sid);
40
+ $clickCode = "clickProduct('$query', '$id', '$position', '$originalPosition', '$currentPageNumber',"
41
+ ."'$similarity', '$sid', '$title', '$pageSize', '$origPageSize', '$channel', 'click');";
42
+ } else {
43
+ $clickCode = '';
44
+ }
45
+
46
+ return $clickCode;
47
+ }
48
+ }
lib/FACTFinder/Xml64/SearchAdapter.php ADDED
@@ -0,0 +1,111 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * search adapter using the xml interface. expects a xml formatted string from the data-provider
5
+ *
6
+ * @author Rudolf Batt <rb@omikron.net>
7
+ * @version $Id: SearchAdapter.php 25893 2010-06-29 08:19:43Z rb $
8
+ * @package FACTFinder\Xml64
9
+ */
10
+ class FACTFinder_Xml64_SearchAdapter extends FACTFinder_Xml65_SearchAdapter
11
+ {
12
+ /**
13
+ * {@inheritdoc}
14
+ * the parameter for the xml result changed in FACT-Finder 6.5, so here it is set different
15
+ */
16
+ protected function init()
17
+ {
18
+ $this->getDataProvider()->setParam('xml', 'true');
19
+ $this->getDataProvider()->setType('Search.ff');
20
+ }
21
+
22
+ /**
23
+ * {@inheritdoc}
24
+ * until versio 6.4 of FACT-Finder there are no slider elements
25
+ *
26
+ * @return FACTFinder_Asn
27
+ **/
28
+ protected function createAsn()
29
+ {
30
+ $xmlResult = $this->getData();
31
+ $asn = array();
32
+
33
+ if (!empty($xmlResult->asn)) {
34
+ $encodingHandler = $this->getEncodingHandler();
35
+ $params = $this->getParamsParser()->getRequestParams();
36
+
37
+ foreach ($xmlResult->asn->group AS $xmlGroup) {
38
+ $groupName = $encodingHandler->encodeServerContentForPage((string)$xmlGroup->attributes()->name);
39
+ $groupUnit = '';
40
+ if (isset($xmlGroup->attributes()->unit)) {
41
+ $groupUnit = strval($xmlGroup->attributes()->unit);
42
+ }
43
+
44
+ $group = FF::getInstance('asnGroup',
45
+ array(),
46
+ $encodingHandler->encodeServerContentForPage((string)$xmlGroup->attributes()->name),
47
+ $encodingHandler->encodeServerContentForPage((string)$xmlGroup->attributes()->detailedLinks),
48
+ $groupUnit,
49
+ false
50
+ );
51
+
52
+ //get filters of the current group
53
+ foreach ($xmlGroup->element AS $xmlFilter) {
54
+ $filterLink = $this->getParamsParser()->createPageLink(
55
+ $this->getParamsParser()->parseParamsFromResultString(trim($xmlFilter->searchParams))
56
+ );
57
+ $filter = FF::getInstance('asnFilterItem',
58
+ $encodingHandler->encodeServerContentForPage(trim($xmlFilter->attributes()->name)),
59
+ $filterLink,
60
+ strval($xmlFilter->attributes()->selected) == 'true',
61
+ strval($xmlFilter->attributes()->count),
62
+ strval($xmlFilter->attributes()->clusterLevel),
63
+ strval($xmlFilter->attributes()->previewImage)
64
+ );
65
+
66
+ $group->addFilter($filter);
67
+ }
68
+
69
+ $asn[] = $group;
70
+ }
71
+ }
72
+ return FF::getInstance('asn', $asn);
73
+ }
74
+
75
+ /**
76
+ * {@inheritdoc}
77
+ * until version 6.4 of FACT-Finder, the products per page options are not delivered, so this method creates an
78
+ * artificial products per page options array, but uses the current set productsPerPage value from the result
79
+ *
80
+ * @return FACTFinder_ProductsPerPageOptions
81
+ */
82
+ protected function createProductsPerPageOptions()
83
+ {
84
+ $pppOptions = array(); //default
85
+ $xmlResult = $this->getData();
86
+
87
+ if (!empty($xmlResult->paging)) {
88
+ $params = $this->getParamsParser()->getRequestParams();
89
+
90
+ $selectedOption = intval($xmlResult->paging->attributes()->productsPerPage);
91
+ $defaultOption = 12;
92
+ $options = array();
93
+
94
+ if ($selectedOption < $defaultOption) {
95
+ $defaultOption = $selectedOption;
96
+ }
97
+ $options[$defaultOption] = $this->getProductsPerPageLink($defaultOption);
98
+ if ($selectedOption != $defaultOption) {
99
+ $options[$selectedOption] = $this->getProductsPerPageLink($selectedOption);
100
+ }
101
+
102
+ $pppOptions = FF::getInstance('productsPerPageOptions', $options, $defaultOption, $selectedOption);
103
+ }
104
+ return $pppOptions;
105
+ }
106
+
107
+ protected function getProductsPerPageLink($pppOption) {
108
+ $params = $this->getParamsParser()->getRequestParams();
109
+ return $this->getParamsParser()->createPageLink($params, array('productsPerPage' => $pppOption));
110
+ }
111
+ }
lib/FACTFinder/Xml65/RecommendationAdapter.php ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * adapter for the factfinder recommendation engine, working with the XML interface of FF6.5
5
+ *
6
+ * @author Rudolf Batt <rb@omikron.net>
7
+ * @version $Id$
8
+ * @package FACTFinder\Xml65
9
+ */
10
+ class FACTFinder_Xml65_RecommendationAdapter extends FACTFinder_Abstract_RecommendationAdapter
11
+ {
12
+
13
+ protected $xmlData = null;
14
+
15
+ /**
16
+ * {@inheritdoc}
17
+ */
18
+ protected function init()
19
+ {
20
+ parent::init();
21
+ $this->log->info("Initializing new recommendation adapter.");
22
+ $this->getDataProvider()->setParam('do', 'getRecommendation');
23
+ $this->getDataProvider()->setParam('format', 'xml');
24
+ $this->getDataProvider()->setType('Recommender.ff');
25
+ }
26
+
27
+ /**
28
+ * try to parse data as xml
29
+ *
30
+ * @throws Exception of data is no valid XML
31
+ * @return SimpleXMLElement
32
+ */
33
+ protected function getData()
34
+ {
35
+ if ($this->xmlData == null) {
36
+ libxml_use_internal_errors(true);
37
+ $data = parent::getData();
38
+ $this->xmlData = new SimpleXMLElement($data); //throws exception on error
39
+ }
40
+ return $this->xmlData;
41
+ }
42
+
43
+ /**
44
+ * creates the recommendation-records.
45
+ * each record has a similarity of 100.0%, because the similarity is not known. the position is just
46
+ * the position at the recommendations result starting from 0 - there is no "original position" at
47
+ * these records.
48
+ *
49
+ * @param string id of the product which should be used to get some recommendations
50
+ * @return array of FACTFinder_Record objects
51
+ *
52
+ */
53
+ protected function createRecommendations() {
54
+ $xmlResult = $this->getData(); //throws exception on error
55
+
56
+ $records = array();
57
+ if (!empty($xmlResult->results)) {
58
+ $count = (int) $xmlResult->results->attributes()->count;
59
+ $encodingHandler = $this->getEncodingHandler();
60
+
61
+ //load result
62
+ foreach($xmlResult->results->record AS $xmlRecord){
63
+
64
+ if ($this->idsOnly) {
65
+ $records[] = FF::getInstance('record', $xmlRecord->attributes()->id);
66
+ continue;
67
+ }
68
+
69
+ // fetch record values
70
+ $fieldValues = array();
71
+ foreach($xmlRecord->field AS $xmlField){
72
+ $fieldName = (string) $xmlField->attributes()->name;
73
+ $fieldValues[$fieldName] = (string) $xmlField;
74
+ }
75
+
76
+ $record = FF::getInstance('record', $xmlRecord->attributes()->id, 100.0, $xmlRecord->attributes()->nr);
77
+ $record->setValues($fieldValues);
78
+ $records[] = $record;
79
+ }
80
+ }
81
+ return FF::getInstance('result', $records, $count);
82
+ }
83
+ }
lib/FACTFinder/Xml65/SearchAdapter.php ADDED
@@ -0,0 +1,493 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * search adapter using the xml interface. expects a xml formated string from the dataprovider
5
+ *
6
+ * @author Rudolf Batt <rb@omikron.net>
7
+ * @version $Id: SearchAdapter.php 25985 2010-06-30 15:31:53Z rb $
8
+ * @package FACTFinder\Xml65
9
+ */
10
+ class FACTFinder_Xml65_SearchAdapter extends FACTFinder_Abstract_SearchAdapter
11
+ {
12
+ protected $status = null;
13
+ protected $isArticleNumberSearch;
14
+ protected $xmlData = null;
15
+
16
+ /**
17
+ * {@inheritdoc}
18
+ */
19
+ protected function init()
20
+ {
21
+ $this->log->info("Initializing new search adapter.");
22
+ $this->getDataProvider()->setParam('format', 'xml');
23
+ $this->getDataProvider()->setType('Search.ff');
24
+ }
25
+
26
+ /**
27
+ * try to parse data as xml
28
+ *
29
+ * @throws Exception of data is no valid XML
30
+ * @return SimpleXMLElement
31
+ */
32
+ protected function getData()
33
+ {
34
+ if ($this->xmlData == null) {
35
+ libxml_use_internal_errors(true);
36
+ $data = parent::getData();
37
+ $this->xmlData = new SimpleXMLElement($data); //throws exception on error
38
+ }
39
+ return $this->xmlData;
40
+ }
41
+
42
+ /**
43
+ * {@inheritdoc}
44
+ *
45
+ * @return string status
46
+ **/
47
+ public function getArticleNumberSearchStatus() {
48
+ if ($this->articleNumberSearchStatus == null) {
49
+
50
+ $this->isArticleNumberSearch = false;
51
+ $this->articleNumberSearchStatus = self::NO_RESULT;
52
+
53
+ if ($this->getStatus() != self::NO_RESULT) {
54
+ $this->loadArticleNumberSearchInformations();
55
+ }
56
+ }
57
+ return $this->articleNumberSearchStatus;
58
+ }
59
+
60
+ /**
61
+ * {@inheritdoc}
62
+ *
63
+ * @return boolean isArticleNumberSearch
64
+ **/
65
+ public function isArticleNumberSearch() {
66
+ if ($this->isArticleNumberSearch === null) {
67
+
68
+ $this->isArticleNumberSearch = false;
69
+
70
+ if ($this->getStatus() != self::NO_RESULT) {
71
+ $this->loadArticleNumberSearchInformations();
72
+ }
73
+ }
74
+ return $this->isArticleNumberSearch;
75
+ }
76
+
77
+ /**
78
+ * fetch article number search status from the xml result
79
+ *
80
+ * @return void
81
+ */
82
+ private function loadArticleNumberSearchInformations() {
83
+ $xmlResult = $this->getData();
84
+ switch($xmlResult->articleNumberSearchStatus){
85
+ case 'nothingFound':
86
+ $this->isArticleNumberSearch = true;
87
+ $this->articleNumberSearchStatus = self::NOTHING_FOUND;
88
+ break;
89
+ case 'resultsFound':
90
+ $this->isArticleNumberSearch = true;
91
+ $this->articleNumberSearchStatus = self::RESULTS_FOUND;
92
+ break;
93
+ case 'noArticleNumberSearch':
94
+ default:
95
+ $this->isArticleNumberSearch = false;
96
+ $this->articleNumberSearchStatus = self::NO_RESULT;
97
+ }
98
+ }
99
+
100
+ /**
101
+ * {@inheritdoc}
102
+ *
103
+ * @return boolean true if search timed out
104
+ **/
105
+ public function isSearchTimedOut()
106
+ {
107
+ $xmlResult = $this->getData();
108
+ if($xmlResult->searchTimedOut == 'true') {
109
+ return true;
110
+ } else {
111
+ return false;
112
+ }
113
+ }
114
+
115
+ /**
116
+ * {@inheritdoc}
117
+ *
118
+ * @return string status
119
+ **/
120
+ public function getStatus()
121
+ {
122
+ if ($this->status == null) {
123
+ $xmlResult = $this->getData();
124
+ switch($xmlResult->searchStatus){
125
+ case 'nothingFound':
126
+ $this->status = self::NOTHING_FOUND;
127
+ break;
128
+ case 'resultsFound':
129
+ $this->status = self::RESULTS_FOUND;
130
+ break;
131
+ default:
132
+ $this->status = self::NO_RESULT;
133
+ }
134
+ }
135
+ return $this->status;
136
+ }
137
+
138
+ /**
139
+ * {@inheritdoc}
140
+ **/
141
+ protected function createSearchParams()
142
+ {
143
+ $breadCrumbTrail = $this->getBreadCrumbTrail();
144
+ if (sizeof($breadCrumbTrail) > 0) {
145
+ $paramString = $breadCrumbTrail[sizeof($breadCrumbTrail)-1]->getUrl();
146
+ $searchParams = $this->getParamsParser()->getFactfinderParamsFromString($paramString);
147
+ } else {
148
+ $searchParams = $this->getParamsParser()->getFactfinderParams();
149
+ }
150
+ return $searchParams;
151
+ }
152
+
153
+ /**
154
+ * {@inheritdoc}
155
+ **/
156
+ protected function createResult()
157
+ {
158
+ //init default values
159
+ $result = array();
160
+ $resultCount = 0;
161
+ $xmlResult = $this->getData();
162
+
163
+ //load result values from the xml element
164
+ if (!empty($xmlResult->results)) {
165
+ $resultCount = (int) $xmlResult->results->attributes()->count;
166
+ $encodingHandler = $this->getEncodingHandler();
167
+
168
+ $paging = $this->getPaging();
169
+ $positionOffset = ($paging->getCurrentPageNumber() - 1) * $this->getProductsPerPageOptions()->getSelectedOption()->getValue();
170
+
171
+ //load result
172
+ $positionCounter = 1;
173
+ foreach($xmlResult->results->record AS $currentRecord){
174
+ // get current position
175
+ $position = $positionOffset + $positionCounter;
176
+ $positionCounter++;
177
+
178
+ // fetch record values
179
+ $fieldValues = array();
180
+ foreach($currentRecord->field AS $current_field){
181
+ $currentFieldname = (string) $current_field->attributes()->name;
182
+ $fieldValues[$currentFieldname] = (string) $current_field;
183
+ }
184
+
185
+ // get original position
186
+ if (isset($fieldValues['__ORIG_POSITION__'])) {
187
+ $origPosition = $fieldValues['__ORIG_POSITION__'];
188
+ unset($fieldValues['__ORIG_POSITION__']);
189
+ } else {
190
+ $origPosition = $position;
191
+ }
192
+
193
+ $result[] = FF::getInstance('record',
194
+ $currentRecord->attributes()->id,
195
+ floatval($currentRecord->attributes()->relevancy),
196
+ $position,
197
+ $origPosition,
198
+ $encodingHandler->encodeServerContentForPage($fieldValues)
199
+ );
200
+ }
201
+ }
202
+ return FF::getInstance('result', $result, $resultCount);
203
+ }
204
+
205
+ /**
206
+ * {@inheritdoc}
207
+ *
208
+ * @return FACTFinder_Asn
209
+ **/
210
+ protected function createAsn()
211
+ {
212
+ $xmlResult = $this->getData();
213
+ $asn = array();
214
+
215
+ if (!empty($xmlResult->asn)) {
216
+ $encodingHandler = $this->getEncodingHandler();
217
+ $params = $this->getParamsParser()->getRequestParams();
218
+
219
+ foreach ($xmlResult->asn->group AS $xmlGroup) {
220
+ $groupName = $encodingHandler->encodeServerContentForPage((string)$xmlGroup->attributes()->name);
221
+ $groupUnit = '';
222
+ if (isset($xmlGroup->attributes()->unit)) {
223
+ $groupUnit = strval($xmlGroup->attributes()->unit);
224
+ }
225
+
226
+ $group = FF::getInstance('asnGroup',
227
+ array(),
228
+ $encodingHandler->encodeServerContentForPage((string)$xmlGroup->attributes()->name),
229
+ $encodingHandler->encodeServerContentForPage((string)$xmlGroup->attributes()->detailedLinks),
230
+ $groupUnit,
231
+ strval($xmlGroup->attributes()->style) == 'SLIDER'
232
+ );
233
+
234
+ //get filters of the current group
235
+ foreach ($xmlGroup->element AS $xmlFilter) {
236
+ $filterLink = $this->getParamsParser()->createPageLink(
237
+ $this->getParamsParser()->parseParamsFromResultString(trim($xmlFilter->searchParams))
238
+ );
239
+
240
+ if ($group->isSliderStyle()) {
241
+ // get last (empty) parameter from the search params property
242
+ $params = $this->getParamsParser()->parseParamsFromResultString(trim($xmlFilter->searchParams));
243
+ end($params);
244
+ $filterLink .= '&'.key($params).'=';
245
+
246
+ $filter = FF::getInstance('asnSliderFilter',
247
+ $filterLink,
248
+ strval($xmlFilter->attributes()->absoluteMin),
249
+ strval($xmlFilter->attributes()->absoluteMax),
250
+ strval($xmlFilter->attributes()->selectedMin),
251
+ strval($xmlFilter->attributes()->selectedMax),
252
+ isset($xmlFilter->attributes()->field) ? strval($xmlFilter->attributes()->field) : ''
253
+ );
254
+ } else {
255
+ $filter = FF::getInstance('asnFilterItem',
256
+ $encodingHandler->encodeServerContentForPage(trim($xmlFilter->attributes()->name)),
257
+ $filterLink,
258
+ strval($xmlFilter->attributes()->selected) == 'true',
259
+ strval($xmlFilter->attributes()->count),
260
+ strval($xmlFilter->attributes()->clusterLevel),
261
+ strval($xmlFilter->attributes()->previewImage),
262
+ isset($xmlFilter->attributes()->field) ? strval($xmlFilter->attributes()->field) : ''
263
+ );
264
+ }
265
+
266
+ $group->addFilter($filter);
267
+ }
268
+
269
+ $asn[] = $group;
270
+ }
271
+ }
272
+ return FF::getInstance('asn', $asn);
273
+ }
274
+
275
+ /**
276
+ * {@inheritdoc}
277
+ *
278
+ * @return array of FACTFinder_SortItem objects
279
+ **/
280
+ protected function createSorting()
281
+ {
282
+ $sorting = array();
283
+ $xmlResult = $this->getData();
284
+
285
+ if (!empty($xmlResult->sorting)) {
286
+ $encodingHandler = $this->getEncodingHandler();
287
+
288
+ foreach ($xmlResult->sorting->sort AS $xmlSortItem) {
289
+ $sortLink = $this->getParamsParser()->createPageLink(
290
+ $this->getParamsParser()->parseParamsFromResultString(trim($xmlSortItem->searchParams))
291
+ );
292
+ $sortItem = FF::getInstance('item',
293
+ $encodingHandler->encodeServerContentForPage(trim($xmlSortItem->attributes()->description)),
294
+ $sortLink,
295
+ strval($xmlSortItem->attributes()->selected) == 'true'
296
+ );
297
+ $sorting[] = $sortItem;
298
+ }
299
+ }
300
+ return $sorting;
301
+ }
302
+
303
+ /**
304
+ * {@inheritdoc}
305
+ *
306
+ * @return array of FACTFinder_Item objects
307
+ **/
308
+ protected function createPaging()
309
+ {
310
+ $paging = null;
311
+ $xmlResult = $this->getData();
312
+
313
+ if (!empty($xmlResult->paging)) {
314
+ $paging = FF::getInstance('paging',
315
+ intval(trim($xmlResult->paging->attributes()->currentPage)),
316
+ intval(trim($xmlResult->paging->attributes()->pageCount)),
317
+ $this->getParamsParser()
318
+ );
319
+ } else {
320
+ $paging = FF::getInstance('paging', 1, 1, $this->getParamsParser());
321
+ }
322
+ return $paging;
323
+ }
324
+
325
+ /**
326
+ * {@inheritdoc}
327
+ *
328
+ * @return FACTFinder_ProductsPerPageOptions
329
+ */
330
+ protected function createProductsPerPageOptions()
331
+ {
332
+ $pppOptions = array(); //default
333
+ $xmlResult = $this->getData();
334
+
335
+ if (!empty($xmlResult->productsPerPageOptions)) {
336
+ $defaultOption = intval(trim($xmlResult->productsPerPageOptions->attributes()->default));
337
+ $selectedOption = intval(trim($xmlResult->productsPerPageOptions->attributes()->selected));
338
+
339
+ $options = array();
340
+ foreach($xmlResult->productsPerPageOptions->option AS $option) {
341
+ $value = intval(trim($option->attributes()->value));
342
+ $url = $this->getParamsParser()->createPageLink(
343
+ $this->getParamsParser()->parseParamsFromResultString(trim($option->searchParams))
344
+ );
345
+ $options[$value] = $url;
346
+ }
347
+ $pppOptions = FF::getInstance('productsPerPageOptions', $options, $defaultOption, $selectedOption);
348
+ }
349
+ return $pppOptions;
350
+ }
351
+
352
+ /**
353
+ * {@inheritdoc}
354
+ *
355
+ * @return array of FACTFinder_BreadCrumbItem objects
356
+ */
357
+ protected function createBreadCrumbTrail()
358
+ {
359
+ $breadCrumbTrail = array();
360
+ $xmlResult = $this->getData();
361
+
362
+ if (!empty($xmlResult->breadCrumbTrail)) {
363
+ $encodingHandler = $this->getEncodingHandler();
364
+
365
+ $breadCrumbCount = count($xmlResult->breadCrumbTrail->item);
366
+ $i = 1;
367
+ foreach ($xmlResult->breadCrumbTrail->item AS $item) {
368
+ $link = $this->getParamsParser()->createPageLink(
369
+ $this->getParamsParser()->parseParamsFromResultString(trim($item->searchParams))
370
+ );
371
+
372
+ $fieldName = '';
373
+ $fieldUnit = '';
374
+ $breadCrumbType = $encodingHandler->encodeServerContentForPage(strval($item->attributes()->type));
375
+ if ($breadCrumbType == 'filter') {
376
+ $fieldName = $encodingHandler->encodeServerContentForPage(strval($item->attributes()->fieldName));
377
+ $fieldUnit = $encodingHandler->encodeServerContentForPage(strval($item->attributes()->fieldUnit));
378
+ }
379
+
380
+ $breadCrumb = FF::getInstance('breadCrumbItem',
381
+ $encodingHandler->encodeServerContentForPage(trim($item->attributes()->value)),
382
+ $link,
383
+ ($i == $breadCrumbCount),
384
+ $breadCrumbType,
385
+ $fieldName,
386
+ $fieldUnit
387
+ );
388
+
389
+ $breadCrumbTrail[] = $breadCrumb;
390
+ $i++;
391
+ }
392
+ }
393
+ return $breadCrumbTrail;
394
+ }
395
+
396
+ /**
397
+ * {@inheritdoc}
398
+ *
399
+ * @return array of FACTFinder_Campaign objects
400
+ */
401
+ protected function createCampaigns()
402
+ {
403
+ $campaigns = array();
404
+ $xmlResult = $this->getData();
405
+
406
+ if (!empty($xmlResult->campaigns)) {
407
+ $encodingHandler = $this->getEncodingHandler();
408
+
409
+ foreach ($xmlResult->campaigns->campaign AS $xmlCampaign) {
410
+ //get redirect
411
+ $redirectUrl = '';
412
+ if (!empty($xmlCampaign->target->destination)) {
413
+ $redirectUrl = $encodingHandler->encodeServerUrlForPageUrl(strval($xmlCampaign->target->destination));
414
+ }
415
+
416
+ $campaign = FF::getInstance('campaign',
417
+ $encodingHandler->encodeServerContentForPage(strval($xmlCampaign->attributes()->name)),
418
+ $encodingHandler->encodeServerContentForPage(strval($xmlCampaign->attributes()->category)),
419
+ $redirectUrl
420
+ );
421
+
422
+ //get feedback
423
+ if (!empty($xmlCampaign->feedback)) {
424
+ $feedback = array();
425
+ foreach ($xmlCampaign->feedback->text as $text) {
426
+ $nr = intval(trim($text->attributes()->nr));
427
+ $feedback[$nr] = $encodingHandler->encodeServerContentForPage((string)$text);
428
+ }
429
+ $campaign->addFeedback($feedback);
430
+ }
431
+
432
+ //get pushed products
433
+ if (!empty($xmlCampaign->pushedProducts)) {
434
+ $pushedProducts = array();
435
+ foreach ($xmlCampaign->pushedProducts->product AS $xmlProduct) {
436
+ $product = FF::getInstance('record', $xmlProduct->attributes()->id, 100);
437
+
438
+ // fetch product values
439
+ $fieldValues = array();
440
+ foreach($xmlProduct->field AS $current_field){
441
+ $currentFieldname = (string) $current_field->attributes()->name;
442
+ $fieldValues[$currentFieldname] = (string) $current_field;
443
+ }
444
+ $product->setValues($encodingHandler->encodeServerContentForPage($fieldValues));
445
+ $pushedProducts[] = $product;
446
+ }
447
+ $campaign->addPushedProducts($pushedProducts);
448
+ }
449
+
450
+ $campaigns[] = $campaign;
451
+ }
452
+ }
453
+ $campaignIterator = FF::getInstance('campaignIterator', $campaigns);
454
+ return $campaignIterator;
455
+ }
456
+
457
+ /**
458
+ * {@inheritdoc}
459
+ *
460
+ * @return array of FACTFinder_SuggestQuery objects
461
+ */
462
+ protected function createSingleWordSearch() {
463
+ $xmlResult = $this->getData();
464
+ $singleWordSearch = array();
465
+ if (isset($xmlResult->singleWordSearch)) {
466
+ $encodingHandler = $this->getEncodingHandler();
467
+ foreach ($xmlResult->singleWordSearch->item AS $item) {
468
+ $query = $encodingHandler->encodeServerContentForPage(strval($item->attributes()->word));
469
+ $singleWordSearch[] = FF::getInstance('suggestQuery',
470
+ $query,
471
+ $this->getParamsParser()->createPageLink(array('query' => $query)),
472
+ intval(trim($item->attributes()->count))
473
+ );
474
+ }
475
+ }
476
+ return $singleWordSearch;
477
+ }
478
+
479
+ /**
480
+ * get error if there is one
481
+ *
482
+ * @return string if error exists, else null
483
+ */
484
+ public function getError()
485
+ {
486
+ $error = null;
487
+ $xmlResult = $this->getData();
488
+ if (!empty($xmlResult->error)) {
489
+ $error = trim(strval($xmlResult->error));
490
+ }
491
+ return $error;
492
+ }
493
+ }
lib/FACTFinder/Xml65/SuggestAdapter.php ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * suggest adapter using the xml interface. expects a xml formated string from the dataprovider
5
+ *
6
+ * @author Rudolf Batt <rb@omikron.net>
7
+ * @version $Id: SuggestAdapter.php 25893 2010-06-29 08:19:43Z rb $
8
+ * @package FACTFinder\Xml65
9
+ */
10
+ class FACTFinder_Xml65_SuggestAdapter extends FACTFinder_Http_SuggestAdapter
11
+ {
12
+ /**
13
+ * {@inheritdoc}
14
+ */
15
+ protected function init()
16
+ {
17
+ parent::init();
18
+ $this->getDataProvider()->setParam('format', 'xml');
19
+ }
20
+
21
+ /**
22
+ * try to parse data as xml
23
+ *
24
+ * @throws Exception of data is no valid XML
25
+ * @return SimpleXMLElement
26
+ */
27
+ protected function getData()
28
+ {
29
+ libxml_use_internal_errors(true);
30
+ return new SimpleXMLElement(parent::getData()); //throws exception on error
31
+ }
32
+
33
+ /**
34
+ * {@inheritdoc}
35
+ * this implementation returns raw suggestions strings
36
+ *
37
+ * @return array of FACTFinder_SuggestQuery objects
38
+ */
39
+ protected function createSuggestions()
40
+ {
41
+ $xmlResult = $this->getData();
42
+ $encodingHandler = $this->getEncodingHandler();
43
+ $paramsParser = $this->getParamsParser();
44
+ $suggest = array();
45
+ if (!empty($xmlResult)) {
46
+ foreach($xmlResult->suggest AS $xmlSuggestQuery) {
47
+ $query = strval($xmlSuggestQuery->attributes()->query);
48
+ $suggest[] = FF::getInstance('suggestQuery',
49
+ $encodingHandler->encodeServerContentForPage($query),
50
+ $paramsParser->createPageLink(array('query' => $query)),
51
+ strval($xmlSuggestQuery->attributes()->hitcount),
52
+ $encodingHandler->encodeServerContentForPage(strval($xmlSuggestQuery->attributes()->type)),
53
+ isset($xmlSuggestQuery->attributes()->hitcount) ? strval($xmlSuggestQuery->attributes()->hitcount) : ''
54
+ );
55
+ }
56
+ }
57
+ return $suggest;
58
+ }
59
+ }
lib/FACTFinder/Xml65/TagCloudAdapter.php ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * tag cloud adapter using the xml interface
5
+ *
6
+ * @author Rudolf Batt <rb@omikron.net>
7
+ * @version $Id: TagCloudAdapter.php 25893 2010-06-29 08:19:43Z rb $
8
+ * @package FACTFinder\Xml65
9
+ */
10
+ class FACTFinder_Xml65_TagCloudAdapter extends FACTFinder_Abstract_TagCloudAdapter
11
+ {
12
+ /**
13
+ * {@inheritdoc}
14
+ *
15
+ * @return void
16
+ **/
17
+ public function init()
18
+ {
19
+ $this->log->info("Initializing new tag cloud adapter.");
20
+ $this->getDataProvider()->setType('WhatsHot.ff');
21
+ $this->getDataProvider()->setParam('do', 'getTagCloud');
22
+ }
23
+
24
+ /**
25
+ * try to parse data as xml
26
+ *
27
+ * @throws Exception of data is no valid XML
28
+ * @return SimpleXMLElement
29
+ */
30
+ protected function getData()
31
+ {
32
+ libxml_use_internal_errors(true);
33
+ return new SimpleXMLElement(parent::getData()); //throws exception on error
34
+ }
35
+
36
+ /**
37
+ * {@inheritdoc}
38
+ *
39
+ * @return array $tagCloud list of FACTFinder_TagQuery items
40
+ **/
41
+ protected function createTagCloud()
42
+ {
43
+ $tagCloud = array();
44
+ $xmlTagCloud = $this->getData();
45
+ if (!empty($xmlTagCloud)) {
46
+ $encodingHandler = $this->getEncodingHandler();
47
+ $ffparams = $this->getParamsParser()->getFactfinderParams();
48
+ foreach($xmlTagCloud->entry AS $xmlEntry) {
49
+ $query = $encodingHandler->encodeServerContentForPage(strval($xmlEntry));
50
+ $tagCloud[] = FF::getInstance('tagQuery',
51
+ $query,
52
+ $this->getParamsParser()->createPageLink(array('query' => $query)),
53
+ ($ffparams->getQuery() == $query),
54
+ $xmlEntry->attributes()->weight,
55
+ $xmlEntry->attributes()->searchCount
56
+ );
57
+ }
58
+ }
59
+ return $tagCloud;
60
+ }
61
+ }
lib/FACTFinder/Xml66/CompareAdapter.php ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * product comparison adapter using the xml interface
5
+ *
6
+ * @author Martin Buettner <martin.buettner@omikron.net>
7
+ * @version $Id: SimilarRecordsAdapter.php 42955 2012-01-25 17:04:47Z mb $
8
+ * @package FACTFinder\Xml66
9
+ */
10
+ class FACTFinder_Xml66_CompareAdapter extends FACTFinder_Abstract_CompareAdapter
11
+ {
12
+ /**
13
+ * {@inheritdoc}
14
+ *
15
+ * @return void
16
+ **/
17
+ public function init() {
18
+ $this->log->info("Initializing new compare adapter.");
19
+ $this->getDataProvider()->setParam('format', 'xml');
20
+ $this->getDataProvider()->setType('Compare.ff');
21
+ }
22
+
23
+ /**
24
+ * try to parse data as xml
25
+ *
26
+ * @throws Exception of data is no valid XML
27
+ * @return SimpleXMLElement
28
+ */
29
+ protected function getData() {
30
+ libxml_use_internal_errors(true);
31
+ return new SimpleXMLElement(parent::getData()); //throws exception on error
32
+ }
33
+
34
+ /**
35
+ * {@inheritdoc}
36
+ *
37
+ * @return array $comparableAttributes of strings (field names as keys, hasDifferences as values)
38
+ **/
39
+ protected function createComparableAttributes() {
40
+ $comparableAttributes = array();
41
+ $xmlComparableAttributes = $this->getData()->attributes;
42
+ if (!empty($xmlComparableAttributes)) {
43
+ foreach($xmlComparableAttributes->attribute AS $currentAttribute){
44
+ $name = (string) $currentAttribute->attributes()->name;
45
+ $comparableAttributes[$name] = ((string) $currentAttribute->attributes()->hasDifferences == "true") ? true : false;
46
+ }
47
+ }
48
+ return $comparableAttributes;
49
+ }
50
+
51
+ /**
52
+ * {@inheritdoc}
53
+ *
54
+ * @return array $comparedRecords list of FACTFinder_Record items
55
+ **/
56
+ protected function createComparedRecords() {
57
+ $comparedRecords = array();
58
+ $xmlComparedRecords = $this->getData()->results;
59
+ if (!empty($xmlComparedRecords)) {
60
+ $encodingHandler = $this->getEncodingHandler();
61
+
62
+ if($this->idsOnly && !$this->attributesUpToDate) {
63
+ $this->createComparableAttributes();
64
+ $this->attributesUpToDate = true;
65
+ }
66
+
67
+ $positionCounter = 1;
68
+ foreach($xmlComparedRecords->record AS $currentRecord) {
69
+ // get current position
70
+ $position = $positionCounter;
71
+ $positionCounter++;
72
+
73
+ // fetch record values
74
+ $fieldValues = array();
75
+ foreach($currentRecord->field AS $current_field){
76
+ $currentFieldname = (string) $current_field->attributes()->name;
77
+ if(!$this->idsOnly || array_key_exists($currentFieldname, $this->comparableAttributes)) {
78
+ $fieldValues[$currentFieldname] = (string) $current_field;
79
+ }
80
+ }
81
+
82
+ // get original position
83
+ if (isset($fieldValues['__ORIG_POSITION__'])) {
84
+ $origPosition = $fieldValues['__ORIG_POSITION__'];
85
+ unset($fieldValues['__ORIG_POSITION__']);
86
+ } else {
87
+ $origPosition = $position;
88
+ }
89
+
90
+ $comparedRecords[] = FF::getInstance('record',
91
+ $currentRecord->attributes()->id,
92
+ floatval($currentRecord->attributes()->relevancy),
93
+ $position,
94
+ $origPosition,
95
+ $encodingHandler->encodeServerContentForPage($fieldValues)
96
+ );
97
+ }
98
+ }
99
+ return $comparedRecords;
100
+ }
101
+ }
lib/FACTFinder/Xml66/RecommendationAdapter.php ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * adapter for the factfinder recommendation engine, working with the XML interface of FF6.6
5
+ *
6
+ * @author Rudolf Batt <rb@omikron.net>
7
+ * @version $Id$
8
+ * @package FACTFinder\Xml66
9
+ */
10
+ class FACTFinder_Xml66_RecommendationAdapter extends FACTFinder_Xml65_RecommendationAdapter
11
+ {
12
+ /**
13
+ * no changes in FF6.6
14
+ **/
15
+ }
lib/FACTFinder/Xml66/SearchAdapter.php ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * search adapter using the xml interface. expects a xml formated string from the dataprovider
5
+ *
6
+ * @author Rudolf Batt <rb@omikron.net>
7
+ * @version $Id: SearchAdapter.php 25985 2010-06-30 15:31:53Z rb $
8
+ * @package FACTFinder\Xml66
9
+ */
10
+ class FACTFinder_Xml66_SearchAdapter extends FACTFinder_Xml65_SearchAdapter
11
+ {
12
+ /**
13
+ * {@inheritdoc}
14
+ **/
15
+ protected function createResult()
16
+ {
17
+ //init default values
18
+ $result = array();
19
+ $resultCount = 0;
20
+ $xmlResult = $this->getData();
21
+
22
+ //load result values from the xml element
23
+ if (!empty($xmlResult->results)) {
24
+ $resultCount = (int) $xmlResult->results->attributes()->count;
25
+ $encodingHandler = $this->getEncodingHandler();
26
+
27
+ $paging = $this->getPaging();
28
+ $positionOffset = ($paging->getCurrentPageNumber() - 1) * $this->getProductsPerPageOptions()->getSelectedOption()->getValue();
29
+
30
+ //load result
31
+ $positionCounter = 1;
32
+ foreach($xmlResult->results->record AS $rawRecord){
33
+ // get current position
34
+ $position = $positionOffset + $positionCounter;
35
+ $positionCounter++;
36
+
37
+ $result[] = $this->getRecordFromRawRecord($rawRecord, $position);
38
+ }
39
+ }
40
+ return FF::getInstance('result', $result, $resultCount);
41
+ }
42
+
43
+ /**
44
+ * {@inheritdoc}
45
+ *
46
+ * @return array of FACTFinder_SingleWordSearchItem objects
47
+ */
48
+ protected function createSingleWordSearch()
49
+ {
50
+ $xmlResult = $this->getData();
51
+ $singleWordSearch = array();
52
+ if (isset($xmlResult->singleWordSearch)) {
53
+ $encodingHandler = $this->getEncodingHandler();
54
+ foreach ($xmlResult->singleWordSearch->item AS $item) {
55
+ $query = $encodingHandler->encodeServerContentForPage(strval($item->attributes()->word));
56
+ $singleWordSearchItem = FF::getInstance('singleWordSearchItem',
57
+ $query,
58
+ $this->getParamsParser()->createPageLink(array('query' => $query)),
59
+ intval(trim($item->attributes()->count))
60
+ );
61
+
62
+ //add preview records
63
+ if (isset($item->record)) {
64
+ $position = 1;
65
+ foreach($item->record AS $rawRecord) {
66
+ $record = $this->getRecordFromRawRecord($rawRecord, $position);
67
+ $singleWordSearchItem->addPreviewRecord($record);
68
+ $position++;
69
+ }
70
+ }
71
+
72
+ $singleWordSearch[] = $singleWordSearchItem;
73
+ }
74
+ }
75
+ return $singleWordSearch;
76
+ }
77
+
78
+ protected function getRecordFromRawRecord(SimpleXmlElement $rawRecord, $position)
79
+ {
80
+ // fetch record values
81
+ $fieldValues = array();
82
+ foreach($rawRecord->field AS $current_field){
83
+ $currentFieldname = (string) $current_field->attributes()->name;
84
+ $fieldValues[$currentFieldname] = (string) $current_field;
85
+ }
86
+
87
+ // get original position
88
+ if (isset($fieldValues['__ORIG_POSITION__'])) {
89
+ $origPosition = $fieldValues['__ORIG_POSITION__'];
90
+ unset($fieldValues['__ORIG_POSITION__']);
91
+ } else {
92
+ $origPosition = $position;
93
+ }
94
+
95
+ $record = FF::getInstance('record',
96
+ $rawRecord->attributes()->id,
97
+ floatval($rawRecord->attributes()->relevancy),
98
+ $position,
99
+ $origPosition,
100
+ $this->getEncodingHandler()->encodeServerContentForPage($fieldValues)
101
+ );
102
+
103
+ if (isset($rawRecord->seoPath)) {
104
+ $record->setSeoPath(strval($rawRecord->seoPath));
105
+ }
106
+
107
+ if (isset($rawRecord->keywords)) {
108
+ foreach($rawRecord->keywords->keyword AS $keyword) {
109
+ $record->addKeyword(strval($keyword));
110
+ }
111
+ }
112
+
113
+ return $record;
114
+ }
115
+ }
lib/FACTFinder/Xml66/SimilarRecordsAdapter.php ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * similar records adapter using the xml interface
5
+ *
6
+ * @author Martin Buettner <martin.buettner@omikron.net>
7
+ * @version $Id: SimilarRecordsAdapter.php 42804 2012-01-20 10:46:43Z mb $
8
+ * @package FACTFinder\Xml66
9
+ */
10
+ class FACTFinder_Xml66_SimilarRecordsAdapter extends FACTFinder_Abstract_SimilarRecordsAdapter
11
+ {
12
+ /**
13
+ * {@inheritdoc}
14
+ *
15
+ * @return void
16
+ **/
17
+ public function init() {
18
+ $this->log->info("Initializing new similar records adapter.");
19
+ $this->getDataProvider()->setParam('format', 'xml');
20
+ $this->getDataProvider()->setType('SimilarRecords.ff');
21
+ }
22
+
23
+ /**
24
+ * try to parse data as xml
25
+ *
26
+ * @throws Exception of data is no valid XML
27
+ * @return SimpleXMLElement
28
+ */
29
+ protected function getData() {
30
+ libxml_use_internal_errors(true);
31
+ return new SimpleXMLElement(parent::getData()); //throws exception on error
32
+ }
33
+
34
+ protected function reloadData() {
35
+ libxml_use_internal_errors(true);
36
+ return new SimpleXMLElement(parent::reloadData()); //throws exception on error
37
+ }
38
+
39
+ /**
40
+ * {@inheritdoc}
41
+ *
42
+ * @param string id of the product which should be used to get similar attributes
43
+ * @return array $similarAttributes of strings (field names as keys)
44
+ **/
45
+ protected function createSimilarAttributes() {
46
+ $similarAttributes = array();
47
+ $xmlSimilarAttributes = $this->reloadData()->similarAttributes;
48
+ if (!empty($xmlSimilarAttributes)) {
49
+ foreach($xmlSimilarAttributes->attribute AS $currentAttribute){
50
+ $currentAttribute = (string) $currentAttribute->attributes()->name;
51
+ $similarAttributes[$currentAttribute] = (string) $currentAttribute;
52
+ }
53
+ }
54
+ return $similarAttributes;
55
+ }
56
+
57
+ /**
58
+ * {@inheritdoc}
59
+ *
60
+ * @param string id of the product which should be used to get similar records
61
+ * @return array $similarRecords list of FACTFinder_Record items
62
+ **/
63
+ protected function createSimilarRecords() {
64
+ $similarRecords = array();
65
+ $xmlSimilarRecords = $this->reloadData()->similarRecords;
66
+ if (!empty($xmlSimilarRecords)) {
67
+ $encodingHandler = $this->getEncodingHandler();
68
+
69
+ $positionCounter = 1;
70
+ foreach($xmlSimilarRecords->record AS $currentRecord) {
71
+ // get current position
72
+ $position = $positionCounter;
73
+ $positionCounter++;
74
+
75
+ if ($this->idsOnly) {
76
+ $similarRecords[] = FF::getInstance('record', $currentRecord->attributes()->id);
77
+ continue;
78
+ }
79
+
80
+ // fetch record values
81
+ $fieldValues = array();
82
+ foreach($currentRecord->field AS $current_field){
83
+ $currentFieldname = (string) $current_field->attributes()->name;
84
+ $fieldValues[$currentFieldname] = (string) $current_field;
85
+ }
86
+
87
+ // get original position
88
+ if (isset($fieldValues['__ORIG_POSITION__'])) {
89
+ $origPosition = $fieldValues['__ORIG_POSITION__'];
90
+ unset($fieldValues['__ORIG_POSITION__']);
91
+ } else {
92
+ $origPosition = $position;
93
+ }
94
+
95
+ $similarRecords[] = FF::getInstance('record',
96
+ $currentRecord->attributes()->id,
97
+ floatval($currentRecord->attributes()->relevancy),
98
+ $position,
99
+ $origPosition,
100
+ $encodingHandler->encodeServerContentForPage($fieldValues)
101
+ );
102
+ }
103
+ }
104
+ return $similarRecords;
105
+ }
106
+ }
lib/FACTFinder/Xml66/SuggestAdapter.php ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * suggest adapter using the xml interface. expects a xml formated string from the dataprovider
5
+ *
6
+ * @author Rudolf Batt <rb@omikron.net>
7
+ * @version $Id: SuggestAdapter.php 25893 2010-06-29 08:19:43Z rb $
8
+ * @package FACTFinder\Xml66
9
+ */
10
+ class FACTFinder_Xml66_SuggestAdapter extends FACTFinder_Xml65_SuggestAdapter
11
+ {
12
+ /**
13
+ * there are no special new features in FF6.6
14
+ */
15
+ }
lib/FACTFinder/Xml66/TagCloudAdapter.php ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * tag cloud adapter using the xml interface
5
+ *
6
+ * @author Rudolf Batt <rb@omikron.net>
7
+ * @version $Id: TagCloudAdapter.php 25893 2010-06-29 08:19:43Z rb $
8
+ * @package FACTFinder\Xml66
9
+ */
10
+ class FACTFinder_Xml66_TagCloudAdapter extends FACTFinder_Xml65_TagCloudAdapter
11
+ {
12
+ /**
13
+ * no changes in FF6.6
14
+ **/
15
+ }
lib/FACTFinder/Xml67/CompareAdapter.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * product comparison adapter using the xml interface
5
+ *
6
+ * @author Rudolf Batt <rb@omikron.net>
7
+ * @version $Id: TagCloudAdapter.php 25893 2010-06-29 08:19:43Z rb $
8
+ * @package FACTFinder\Xml67
9
+ */
10
+ class FACTFinder_Xml67_CompareAdapter extends FACTFinder_Xml66_CompareAdapter
11
+ {
12
+ }
lib/FACTFinder/Xml67/ProductCampaignAdapter.php ADDED
@@ -0,0 +1,161 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * product campaign adapter using the xml interface
5
+ *
6
+ * @author Rudolf Batt <rb@omikron.net>, Martin Buettner <martin.buettner@omikron.net>
7
+ * @version $Id: ProductCampaignAdapter.php 43440 2012-02-08 12:42:13Z martin.buettner $
8
+ * @package FACTFinder\Xml67
9
+ */
10
+ class FACTFinder_Xml67_ProductCampaignAdapter extends FACTFinder_Abstract_ProductCampaignAdapter
11
+ {
12
+ protected $xmlData = null;
13
+
14
+ /**
15
+ * {@inheritdoc}
16
+ *
17
+ * @return void
18
+ **/
19
+ public function init()
20
+ {
21
+ $this->log->info("Initializing new product campaign adapter.");
22
+ $this->getDataProvider()->setType('ProductCampaign.ff');
23
+ $this->getDataProvider()->setParam('format', 'xml');
24
+ $this->getDataProvider()->setParam('do', 'getProductCampaigns');
25
+ }
26
+
27
+ /**
28
+ * try to parse data as xml
29
+ *
30
+ * @throws Exception of data is no valid XML
31
+ * @return SimpleXMLElement
32
+ */
33
+ protected function getData()
34
+ {
35
+ if ($this->xmlData == null) {
36
+ libxml_use_internal_errors(true);
37
+ $data = parent::getData();
38
+ $this->xmlData = new SimpleXMLElement($data); //throws exception on error
39
+ }
40
+ return $this->xmlData;
41
+ }
42
+
43
+ /**
44
+ * {@inheritdoc}
45
+ *
46
+ * @return array of FACTFinder_Campaign objects
47
+ */
48
+ protected function createCampaigns()
49
+ {
50
+ $campaigns = array();
51
+ $xmlResult = $this->getData();
52
+
53
+ if (!empty($xmlResult->campaigns)) {
54
+ $encodingHandler = $this->getEncodingHandler();
55
+ $paramsParser = $this->getParamsParser();
56
+
57
+ foreach ($xmlResult->campaigns->campaign AS $xmlCampaign) {
58
+ //get redirect
59
+ $redirectUrl = '';
60
+ if ($xmlCampaign->attributes()->flavour == 'REDIRECT') {
61
+ $redirectUrl = $encodingHandler->encodeServerUrlForPageUrl(strval($xmlCampaign->target->destination));
62
+ }
63
+
64
+ $campaign = FF::getInstance('campaign',
65
+ $encodingHandler->encodeServerContentForPage(strval($xmlCampaign->attributes()->name)),
66
+ $encodingHandler->encodeServerContentForPage(strval($xmlCampaign->attributes()->category)),
67
+ $redirectUrl
68
+ );
69
+
70
+ // get feedback
71
+
72
+ if ($xmlCampaign->attributes()->flavour == 'FEEDBACK') {
73
+
74
+ // here is the new feature: getting feedback texts from labels instead of number indices, if available
75
+ if (!empty($xmlCampaign->feedback)) {
76
+ $feedback = array();
77
+ foreach ($xmlCampaign->feedback->text as $text) {
78
+ if(isset($text->attributes()->label)) {
79
+ $label = trim($text->attributes()->label);
80
+ } else {
81
+ $label = trim($text->attributes()->nr);
82
+ }
83
+ $feedback[$label] = $encodingHandler->encodeServerContentForPage((string)$text);
84
+ }
85
+ $campaign->addFeedback($feedback);
86
+ }
87
+
88
+ //get pushed products
89
+ if (!empty($xmlCampaign->pushedProducts)) {
90
+ $pushedProducts = array();
91
+ foreach ($xmlCampaign->pushedProducts->product AS $xmlProduct) {
92
+ $product = FF::getInstance('record', $xmlProduct->attributes()->id, 100);
93
+
94
+ // fetch product values
95
+ $fieldValues = array();
96
+ foreach($xmlProduct->field AS $current_field){
97
+ $currentFieldname = (string) $current_field->attributes()->name;
98
+ $fieldValues[$currentFieldname] = (string) $current_field;
99
+ }
100
+ $product->setValues($encodingHandler->encodeServerContentForPage($fieldValues));
101
+ $pushedProducts[] = $product;
102
+ }
103
+ $campaign->addPushedProducts($pushedProducts);
104
+ }
105
+ }
106
+
107
+ //get advisor
108
+ if ($xmlCampaign->attributes()->flavour == 'ADVISOR') {
109
+ $activeQuestions = array();
110
+
111
+ // The active questions can still be empty if we have already moved down the whole question tree (while the search query still fulfills the campaign condition)
112
+ if (!empty($xmlCampaign->advisor->activeQuestions)) {
113
+ foreach($xmlCampaign->advisor->activeQuestions->question AS $xmlQuestion) {
114
+ $activeQuestions[] = $this->loadAdvisorQuestion($xmlQuestion);
115
+ }
116
+ }
117
+ $campaign->addActiveQuestions($activeQuestions);
118
+
119
+ // Fetch advisor tree if it exists
120
+ $advisorTree = array();
121
+
122
+ if (!empty($xmlCampaign->advisor->advisorTree)) {
123
+ foreach($xmlCampaign->advisor->advisorTree->question AS $xmlQuestion) {
124
+ $advisorTree[] = $this->loadAdvisorQuestion($xmlQuestion, true);
125
+ }
126
+ }
127
+ $campaign->addToAdvisorTree($advisorTree);
128
+ }
129
+
130
+ $campaigns[] = $campaign;
131
+ }
132
+ }
133
+ $campaignIterator = FF::getInstance('campaignIterator', $campaigns);
134
+ return $campaignIterator;
135
+ }
136
+
137
+ protected function loadAdvisorQuestion($xmlQuestion, $recursive = false) {
138
+ $encodingHandler = $this->getEncodingHandler();
139
+ $paramsParser = $this->getParamsParser();
140
+
141
+ $answers = array();
142
+
143
+ // Fetch answers. Follow-up questions are ignored here.
144
+ foreach($xmlQuestion->answer AS $xmlAnswer) {
145
+ $text = $encodingHandler->encodeServerContentForPage((string)$xmlAnswer->text);
146
+ $params = $paramsParser->createPageLink($paramsParser->parseParamsFromResultString($xmlAnswer->params));
147
+ $subquestions = array();
148
+ if ($recursive) {
149
+ foreach($xmlAnswer->question AS $xmlSubquestion) {
150
+ $subquestions[] = $this->loadAdvisorQuestion($xmlSubquestion, true);
151
+ }
152
+ }
153
+ $answer = FF::getInstance('advisorAnswer', $text, $params, $subquestions);
154
+ $answers[] = $answer;
155
+ }
156
+
157
+ return FF::getInstance('advisorQuestion', $encodingHandler->encodeServerContentForPage((string)$xmlQuestion->text), $answers);
158
+ }
159
+
160
+ }
161
+
lib/FACTFinder/Xml67/RecommendationAdapter.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * adapter for the factfinder recommendation engine, working with the XML interface of FF6.7
5
+ *
6
+ * @author Rudolf Batt <rb@omikron.net>
7
+ * @version $Id$
8
+ * @package FACTFinder\Xml67
9
+ */
10
+ class FACTFinder_Xml67_RecommendationAdapter extends FACTFinder_Xml66_RecommendationAdapter
11
+ {
12
+ /**
13
+ * Set ids of products to base recommendation on
14
+ *
15
+ * @param array $productIds list of integers
16
+ **/
17
+ public function setProductIds($productIds) {
18
+ $this->productIds = $productIds;
19
+ $this->getDataProvider()->setArrayParam('id', $productIds);
20
+ $this->recommendationUpToDate = false;
21
+ }
22
+
23
+ /**
24
+ * Adds an id to the list of products to base recommendation on
25
+ *
26
+ * @param int $productId
27
+ **/
28
+ public function addProductId($productId) {
29
+ $this->productIds[] = $productId;
30
+ $this->getDataProvider()->setArrayParam('id', $this->productIds);
31
+ $this->recommendationUpToDate = false;
32
+ }
33
+ }
lib/FACTFinder/Xml67/SearchAdapter.php ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * search adapter using the xml interface. expects a xml formated string from the dataprovider
5
+ *
6
+ * @author Rudolf Batt <rb@omikron.net>
7
+ * @version $Id: SearchAdapter.php 25985 2010-06-30 15:31:53Z rb $
8
+ * @package FACTFinder\Xml67
9
+ */
10
+ class FACTFinder_Xml67_SearchAdapter extends FACTFinder_Xml66_SearchAdapter
11
+ {
12
+ /**
13
+ * {@inheritdoc}
14
+ *
15
+ * @return array of FACTFinder_Campaign objects
16
+ */
17
+ protected function createCampaigns()
18
+ {
19
+ $campaigns = array();
20
+ $xmlResult = $this->getData();
21
+
22
+ if (!empty($xmlResult->campaigns)) {
23
+ $encodingHandler = $this->getEncodingHandler();
24
+ $paramsParser = $this->getParamsParser();
25
+
26
+ foreach ($xmlResult->campaigns->campaign AS $xmlCampaign) {
27
+ //get redirect
28
+ $redirectUrl = '';
29
+ if ($xmlCampaign->attributes()->flavour == 'REDIRECT') {
30
+ $redirectUrl = $encodingHandler->encodeServerUrlForPageUrl(strval($xmlCampaign->target->destination));
31
+ }
32
+
33
+ $campaign = FF::getInstance('campaign',
34
+ $encodingHandler->encodeServerContentForPage(strval($xmlCampaign->attributes()->name)),
35
+ $encodingHandler->encodeServerContentForPage(strval($xmlCampaign->attributes()->category)),
36
+ $redirectUrl
37
+ );
38
+
39
+ // get feedback
40
+
41
+ if ($xmlCampaign->attributes()->flavour == 'FEEDBACK') {
42
+
43
+ // here is the new feature: getting feedback texts from labels instead of number indices, if available
44
+ if (!empty($xmlCampaign->feedback)) {
45
+ $feedback = array();
46
+ foreach ($xmlCampaign->feedback->text as $text) {
47
+ if(isset($text->attributes()->label)) {
48
+ $label = trim($text->attributes()->label);
49
+ } else {
50
+ $label = trim($text->attributes()->nr);
51
+ }
52
+ $feedback[$label] = $encodingHandler->encodeServerContentForPage((string)$text);
53
+ }
54
+ $campaign->addFeedback($feedback);
55
+ }
56
+
57
+ //get pushed products
58
+ if (!empty($xmlCampaign->pushedProducts)) {
59
+ $pushedProducts = array();
60
+ foreach ($xmlCampaign->pushedProducts->product AS $xmlProduct) {
61
+ $product = FF::getInstance('record', $xmlProduct->attributes()->id, 100);
62
+
63
+ // fetch product values
64
+ $fieldValues = array();
65
+ foreach($xmlProduct->field AS $current_field){
66
+ $currentFieldname = (string) $current_field->attributes()->name;
67
+ $fieldValues[$currentFieldname] = (string) $current_field;
68
+ }
69
+ $product->setValues($encodingHandler->encodeServerContentForPage($fieldValues));
70
+ $pushedProducts[] = $product;
71
+ }
72
+ $campaign->addPushedProducts($pushedProducts);
73
+ }
74
+ }
75
+
76
+ //get advisor
77
+ if ($xmlCampaign->attributes()->flavour == 'ADVISOR') {
78
+ $activeQuestions = array();
79
+
80
+ // The active questions can still be empty if we have already moved down the whole question tree (while the search query still fulfills the campaign condition)
81
+ if (!empty($xmlCampaign->advisor->activeQuestions)) {
82
+ foreach($xmlCampaign->advisor->activeQuestions->question AS $xmlQuestion) {
83
+ $activeQuestions[] = $this->loadAdvisorQuestion($xmlQuestion);
84
+ }
85
+ }
86
+ $campaign->addActiveQuestions($activeQuestions);
87
+
88
+ // Fetch advisor tree if it exists
89
+ $advisorTree = array();
90
+
91
+ if (!empty($xmlCampaign->advisor->advisorTree)) {
92
+ foreach($xmlCampaign->advisor->advisorTree->question AS $xmlQuestion) {
93
+ $advisorTree[] = $this->loadAdvisorQuestion($xmlQuestion, true);
94
+ }
95
+ }
96
+ $campaign->addToAdvisorTree($advisorTree);
97
+ }
98
+
99
+ $campaigns[] = $campaign;
100
+ }
101
+ }
102
+ $campaignIterator = FF::getInstance('campaignIterator', $campaigns);
103
+ return $campaignIterator;
104
+ }
105
+
106
+ protected function loadAdvisorQuestion($xmlQuestion, $recursive = false) {
107
+ $encodingHandler = $this->getEncodingHandler();
108
+ $paramsParser = $this->getParamsParser();
109
+
110
+ $answers = array();
111
+
112
+ // Fetch answers. Follow-up questions are ignored here.
113
+ foreach($xmlQuestion->answer AS $xmlAnswer) {
114
+ $text = $encodingHandler->encodeServerContentForPage((string)$xmlAnswer->text);
115
+ $params = $paramsParser->createPageLink($paramsParser->parseParamsFromResultString($xmlAnswer->params));
116
+ $subquestions = array();
117
+ if ($recursive) {
118
+ foreach($xmlAnswer->question AS $xmlSubquestion) {
119
+ $subquestions[] = $this->loadAdvisorQuestion($xmlSubquestion, true);
120
+ }
121
+ }
122
+ $answer = FF::getInstance('advisorAnswer', $text, $params, $subquestions);
123
+ $answers[] = $answer;
124
+ }
125
+
126
+ return FF::getInstance('advisorQuestion', $encodingHandler->encodeServerContentForPage((string)$xmlQuestion->text), $answers);
127
+ }
128
+ }
lib/FACTFinder/Xml67/SimilarRecordsAdapter.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * similar records adapter using the xml interface
5
+ *
6
+ * @author Rudolf Batt <rb@omikron.net>
7
+ * @version $Id: TagCloudAdapter.php 25893 2010-06-29 08:19:43Z rb $
8
+ * @package FACTFinder\Xml67
9
+ */
10
+ class FACTFinder_Xml67_SimilarRecordsAdapter extends FACTFinder_Xml66_SimilarRecordsAdapter
11
+ {
12
+ }
lib/FACTFinder/Xml67/SuggestAdapter.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * suggest adapter using the xml interface. expects a xml formated string from the dataprovider
5
+ *
6
+ * @author Rudolf Batt <rb@omikron.net>
7
+ * @version $Id: SuggestAdapter.php 25893 2010-06-29 08:19:43Z rb $
8
+ * @package FACTFinder\Xml67
9
+ */
10
+ class FACTFinder_Xml67_SuggestAdapter extends FACTFinder_Xml66_SuggestAdapter
11
+ {
12
+ }
lib/FACTFinder/Xml67/TagCloudAdapter.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * tag cloud adapter using the xml interface
5
+ *
6
+ * @author Rudolf Batt <rb@omikron.net>
7
+ * @version $Id: TagCloudAdapter.php 25893 2010-06-29 08:19:43Z rb $
8
+ * @package FACTFinder\Xml67
9
+ */
10
+ class FACTFinder_Xml67_TagCloudAdapter extends FACTFinder_Xml66_TagCloudAdapter
11
+ {
12
+ }
lib/FACTFinderCustom/Configuration.php ADDED
@@ -0,0 +1,297 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * this class implements the FACTFinder configuration interface and uses the Zend_Config class. so it's like a decorator
5
+ * for the Zend_Config
6
+ *
7
+ * @package FACTFinder\Common
8
+ */
9
+ class FACTFinderCustom_Configuration implements FACTFinder_Abstract_Configuration
10
+ {
11
+ const HTTP_AUTH = 'http';
12
+ const SIMPLE_AUTH = 'simple';
13
+ const ADVANCED_AUTH = 'advanced';
14
+ const XML_CONFIG_PATH = 'factfinder/search/';
15
+
16
+ private $config;
17
+ private $authType;
18
+ private $pageMappings;
19
+ private $serverMappings;
20
+ private $pageIgnores;
21
+ private $serverIgnores;
22
+ private $requiredPageParams;
23
+ private $requiredServerParams;
24
+ private $storeId = null;
25
+
26
+ public function __construct($config = null)
27
+ {
28
+ $this->config = new Varien_Object($config);
29
+ if(is_array($config)){
30
+ $this->config->setData($config);
31
+ }
32
+ }
33
+
34
+ /**
35
+ * @return string
36
+ */
37
+ public function getVersion() {
38
+ return $this->getCustomValue('version');
39
+ }
40
+
41
+ /**
42
+ * @return boolean
43
+ */
44
+ public function isDebugEnabled() {
45
+ return $this->getCustomValue('debug') == 'true';
46
+ }
47
+
48
+ /**
49
+ * @param string name
50
+ * @return string value
51
+ */
52
+ public function getCustomValue($name)
53
+ {
54
+ if(!$this->config->hasData($name)){
55
+ try{
56
+ $this->config->setData($name, Mage::getStoreConfig(self::XML_CONFIG_PATH.$name, $this->storeId));
57
+ }catch (Exception $e){
58
+ $this->config->setData($name, null);
59
+ }
60
+ }
61
+ return $this->config->getData($name);
62
+ }
63
+
64
+ public function __sleep() {
65
+
66
+ foreach(get_class_methods($this) as $method){
67
+ if(substr($method, 0, 3) != 'get'
68
+ || $method == 'getCustomValue'){
69
+ continue;
70
+ }
71
+ call_user_func(array(&$this, $method));
72
+ }
73
+ return array('config');
74
+ }
75
+
76
+ /**
77
+ * @deprecated because of wrong spelling; use getRequestProtocol() instead
78
+ * @return string
79
+ */
80
+ public function getRequestProtokoll() {
81
+ return $this->getRequestProtocol();
82
+ }
83
+
84
+ /**
85
+ * @return string
86
+ */
87
+ public function getRequestProtocol() {
88
+ $protocol = $this->getCustomValue('protocol');
89
+ // legacy code because of wrong spelling
90
+ if (!$protocol) {
91
+ $protocol = $this->getCustomValue('protokoll');
92
+ }
93
+ return $protocol;
94
+ }
95
+
96
+ /**
97
+ * @return string
98
+ */
99
+ public function getServerAddress() {
100
+ return $this->getCustomValue('address');
101
+ }
102
+
103
+ /**
104
+ * @return int
105
+ */
106
+ public function getServerPort() {
107
+ return $this->getCustomValue('port');
108
+ }
109
+
110
+ /**
111
+ * @return string
112
+ */
113
+ public function getContext() {
114
+ return $this->getCustomValue('context');
115
+ }
116
+
117
+ /**
118
+ * @return string
119
+ */
120
+ public function getChannel() {
121
+ return $this->getCustomValue('channel');
122
+ }
123
+
124
+ /**
125
+ * @return string
126
+ */
127
+ public function getLanguage() {
128
+ return $this->getCustomValue('language');
129
+ }
130
+
131
+ /**
132
+ * @return string
133
+ */
134
+ public function getAuthUser() {
135
+ return $this->getCustomValue('auth_user');
136
+ }
137
+
138
+ /**
139
+ * @return string
140
+ */
141
+ public function getAuthPasswort() {
142
+ return $this->getCustomValue('auth_password');
143
+ }
144
+
145
+ /**
146
+ * @return boolean
147
+ */
148
+ public function isHttpAuthenticationType() {
149
+ return $this->getAuthType() == self::HTTP_AUTH;
150
+ }
151
+
152
+ /**
153
+ * @return boolean
154
+ */
155
+ public function isSimpleAuthenticationType() {
156
+ return $this->getAuthType() == self::SIMPLE_AUTH;
157
+ }
158
+
159
+ /**
160
+ * @return boolean
161
+ */
162
+ public function isAdvancedAuthenticationType() {
163
+ return $this->getAuthType() == self::ADVANCED_AUTH;
164
+ }
165
+
166
+ private function getAuthType() {
167
+ if ($this->authType == null) {
168
+ $this->authType = $this->getCustomValue('auth_type');
169
+ if ( $this->authType != self::HTTP_AUTH
170
+ && $this->authType != self::SIMPLE_AUTH
171
+ && $this->authType != self::ADVANCED_AUTH ) {
172
+ $this->authType = self::HTTP_AUTH;
173
+ }
174
+ }
175
+ return $this->authType;
176
+ }
177
+
178
+ /**
179
+ * @return string
180
+ */
181
+ public function getAdvancedAuthPrefix() {
182
+ return $this->getCustomValue('auth_advancedPrefix');
183
+ }
184
+
185
+ /**
186
+ * @return string
187
+ */
188
+ public function getAdvancedAuthPostfix(){
189
+ return $this->getCustomValue('auth_advancedPostfix');
190
+ }
191
+
192
+ /**
193
+ * {@inheritdoc}
194
+ *
195
+ * @return array
196
+ */
197
+ public function getPageMappings() {
198
+ return array();
199
+ }
200
+
201
+ /**
202
+ * {@inheritdoc}
203
+ *
204
+ * @return array
205
+ */
206
+ public function getServerMappings() {
207
+ return array();
208
+ }
209
+
210
+ /**
211
+ * {@inheritdoc}
212
+ *
213
+ * @return array with string as key and boolean true as value for each of them
214
+ */
215
+ public function getIgnoredPageParams() {
216
+ return array(
217
+ 'channel' => true,
218
+ 'format' => true,
219
+ 'log' => true,
220
+ 'productsPerPage' => true,
221
+ 'query' => true
222
+ );
223
+ }
224
+
225
+ /**
226
+ * {@inheritdoc}
227
+ *
228
+ * @return array with string as key and boolean true as value for each of them
229
+ */
230
+ public function getIgnoredServerParams() {
231
+ return array();
232
+ }
233
+
234
+ /**
235
+ * {@inheritdoc}
236
+ *
237
+ * @return array string to string map (param-name as array-key; default value as array-value)
238
+ */
239
+ public function getRequiredPageParams(){
240
+ return array();
241
+ }
242
+
243
+ /**
244
+ * {@inheritdoc}
245
+ *
246
+ * @return array string to string map (param-name as array-key; default value as array-value)
247
+ */
248
+ function getRequiredServerParams(){
249
+ return array();
250
+ }
251
+
252
+
253
+ /**
254
+ * {@inheritdoc}
255
+ *
256
+ * @return string
257
+ */
258
+ function getPageContentEncoding() {
259
+ return $this->getCustomValue('pageContent');
260
+ }
261
+
262
+ /**
263
+ * {@inheritdoc}
264
+ *
265
+ * @return string
266
+ */
267
+ function getPageUrlEncoding() {
268
+ return $this->getCustomValue('pageURI');
269
+ }
270
+
271
+ /**
272
+ * {@inheritdoc}
273
+ *
274
+ * @return string
275
+ */
276
+ function getServerUrlEncoding() {
277
+ return $this->getCustomValue('serverURI');
278
+ }
279
+
280
+
281
+ /**
282
+ * Allows to catch configuration for certain store id.
283
+ * If given store id differs from internal store id, then configuration is cleared.
284
+ *
285
+ * @param int $storeId
286
+ * @return FACTFinderCustom_Configuration
287
+ */
288
+ public function setStoreId($storeId) {
289
+ if ($this->storeId != $storeId) {
290
+ $this->config = new Varien_Object();
291
+ }
292
+
293
+ $this->storeId = $storeId;
294
+
295
+ return $this;
296
+ }
297
+ }
package.xml ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <package>
3
+ <name>Flagbit_Factfinder</name>
4
+ <version>3.3.6</version>
5
+ <stability>stable</stability>
6
+ <license>GPL</license>
7
+ <channel>community</channel>
8
+ <extends/>
9
+ <summary>Integrates the FACT-Finder for improved product search functionality.</summary>
10
+ <description>Integrates the FACT-Finder for improved product search functionality.</description>
11
+ <notes>bugfix: dont fail if products campaigns cant be loaded.
12
+ bugfix: dont use product campaigns, if campaigns are disabled.
13
+ task: show ff search form only if suggest is enabled
14
+ task: apply cluster level into attribute objects
15
+ task: flush output buffer for each bulk on product export</notes>
16
+ <authors><author><name>Flagbit GmbH Co. KG</name><user>auto-converted</user><email>magento@flagbit.de</email></author></authors>
17
+ <date>2012-06-15</date>
18
+ <time>12:36:59</time>
19
+ <contents><target name="mageetc"><dir><dir><file name="factfinder.xml" hash="ca4dac634339217dd2ee6e8dc477d694"/></dir><dir name="modules"><file name="Flagbit_FactFinder.xml" hash="99c6b4e5981ac7592830a9fb3f5e5a0e"/></dir></dir></target><target name="magedesign"><dir><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="layout"><file name="factfinder.xml" hash="5e5cb94967917aa2784d19434d02b2d4"/></dir><dir name="template"><dir name="factfinder"><file name="cockpit.phtml" hash="5fe632ad1c700fe432061be976837a3d"/></dir></dir></dir></dir></dir><dir name="frontend"><dir name="base"><dir name="default"><dir name="layout"><file name="factfinder.xml" hash="b4e442334228676e8847236bdc20bd25"/></dir><dir name="template"><dir name="factfinder"><file name="form.mini.phtml" hash="54045a15eb78bea151f518303773ed0e"/><file name="logo.phtml" hash="7a40d67bf648e65345f69b2cf9d3c6b6"/><file name="scic.phtml" hash="3553a9f0f3c66015610f4c7f1d770a51"/><dir name="campaign"><file name="advisory.phtml" hash="d0ef29b97aa4c3bdfa2b94596beb5b21"/><file name="feedback.phtml" hash="a44c2521e961cfb62b4b89ad0cb71b15"/><dir name="cart"><file name="advisory.phtml" hash="bb994272a6daaaba298a38023f6db212"/><file name="feedback.phtml" hash="01fa6a9cd024a2a8edaea7013b00fc89"/></dir></dir><dir name="filter"><file name="slider.phtml" hash="80e4e9e1c81437fe41b6a52d98e73549"/></dir></dir></dir></dir></dir></dir></dir></target><target name="magelocale"><dir><dir name="de_DE"><file name="Flagbit_FactFinder.csv" hash="c167467f3ad4aa0ae798f5e0c9dce0d6"/></dir></dir></target><target name="magelib"><dir><dir name="FACTFinder"><file name="AdvisorAnswer.php" hash="873206d7ff713e4dbe8d12035236fa88"/><file name="AdvisorQuestion.php" hash="45fc864b18cb650ea7ab6ad69fe4d2cf"/><file name="Asn.php" hash="415d7ca6e57fce1c2dc79a398f277a8e"/><file name="AsnFilterItem.php" hash="823ca331d4f0fb96cdaba37837eb4cf4"/><file name="AsnGroup.php" hash="eb5f98e61330d2086a6f2cbed9b22e2b"/><file name="AsnSliderFilter.php" hash="93960390f4b25235cc6b3fb0ac6e607f"/><file name="BreadCrumbItem.php" hash="926f78a0bdb1331e271b6027d639dcbd"/><file name="Campaign.php" hash="fb71fc56c52bafbf54928478e29a36c2"/><file name="CampaignIterator.php" hash="70ebfc5ab5db712f7bad1e9fff823868"/><file name="Configuration.php" hash="b203f9bb455cdb7d67bca04568ca90db"/><file name="EncodingHandler.php" hash="3cf4f8c653e2cf06101476c6ed0c5d91"/><file name="Item.php" hash="82d6aa160364f1065d905d4bfb81595e"/><file name="Loader.php" hash="f90769906b975860d756db2c7c90bcef"/><file name="Paging.php" hash="1e00f8a23eb7c77e25669662fa96e5d4"/><file name="Parameters.php" hash="3cff8bd17aae5a045eb8bdc9da7f36de"/><file name="ParametersParser.php" hash="32901cab2b4ac273707248a353c0e5d8"/><file name="ProductsPerPageOptions.php" hash="00d5fefb4798df35e5eb59ba7c520d21"/><file name="Record.php" hash="13d6d9d64b6914706866450869b38206"/><file name="Result.php" hash="bc67777850ff18b7784c48bb8f5fbd20"/><file name="SingleWordSearchItem.php" hash="3b806c3d26785f0260d09abe6469c999"/><file name="SuggestQuery.php" hash="9aaa4f18c5369acfe0dcb387245e4a75"/><file name="TagQuery.php" hash="a35b69db11cb856225c00f103b7c16ab"/><file name="Util.php" hash="7f3c81e2bd95a5c61365e8f2426c258e"/><dir name="Abstract"><file name="Adapter.php" hash="469470db8fe9e148922e56ae37ca3862"/><file name="CompareAdapter.php" hash="7ec1139255b96d45b9e29973cfb0ec95"/><file name="Configuration.php" hash="7335710c0e999b3b4d3274f356d871fc"/><file name="DataProvider.php" hash="39dde70290a61f81d19200d36e063880"/><file name="ProductCampaignAdapter.php" hash="58c555e5e704e91c16cb9be5fc82e218"/><file name="RecommendationAdapter.php" hash="1881e3fa29e82a898c7ee3936650fdc7"/><file name="ScicAdapter.php" hash="478dc65ca80eef22696d2b0f4d83167c"/><file name="SearchAdapter.php" hash="48e692f054663c7fa7349c96d0452403"/><file name="SimilarRecordsAdapter.php" hash="302fe55861cef886abd6e210a501a4b3"/><file name="SuggestAdapter.php" hash="1793a1cafe52a21d87b7e9b0a5b4379e"/><file name="TagCloudAdapter.php" hash="8caf392c3a41b31ecf4a239d406576fc"/></dir><dir name="Http"><file name="DataProvider.php" hash="23d3d4dea4c282467ebec881d6571633"/><file name="DummyProvider.php" hash="b4b3991dd1263291a286e3672509f640"/><file name="ParallelDataProvider.php" hash="1e3c196ca9db498d556f15e4f3a613ba"/><file name="ScicAdapter.php" hash="4c7f7f3f689e073976bf37cf6ccfbd02"/><file name="SuggestAdapter.php" hash="f9364c65034848444e2928617f71c357"/></dir><dir name="Logger"><file name="BlackHole.php" hash="a69e509021e53c4605606b0a8b306506"/><file name="LoggerInterface.php" hash="1528b92855ea10d4166cea56e64facd5"/></dir><dir name="Xml64"><file name="SearchAdapter.php" hash="d3ce38946d9df3c96e117b1a0a196b0c"/></dir><dir name="Xml65"><file name="RecommendationAdapter.php" hash="d9c1d57dba84ef5db4dc624c788b91dc"/><file name="SearchAdapter.php" hash="71b0cb4554b98cc7f7d74cd6754bf3cc"/><file name="SuggestAdapter.php" hash="f9742b1c720542d01ec622c6d65beea4"/><file name="TagCloudAdapter.php" hash="290ce886957e6760c9a3bdc5dec19e4f"/></dir><dir name="Xml66"><file name="CompareAdapter.php" hash="5ebc1da804fb2f27cdc6ab911d823f14"/><file name="RecommendationAdapter.php" hash="94cd09e149d85182a6b13773b4c6c601"/><file name="SearchAdapter.php" hash="e178a14e3173c123f38df9312030cdd3"/><file name="SimilarRecordsAdapter.php" hash="669541b29f87955d45d315545a1951bf"/><file name="SuggestAdapter.php" hash="982290e42670453a9597279ffe5fa86c"/><file name="TagCloudAdapter.php" hash="52a7937a07070f2477ccdb2185cdaab8"/></dir><dir name="Xml67"><file name="CompareAdapter.php" hash="f58ea46c0f0a634d2753ff4627937c3d"/><file name="ProductCampaignAdapter.php" hash="6a81f02658445dabc1f997b865e385d5"/><file name="RecommendationAdapter.php" hash="bdbcd5a489b2dc21555aa6db0a044eb3"/><file name="SearchAdapter.php" hash="894f602ab8736307a932354010ae8a07"/><file name="SimilarRecordsAdapter.php" hash="75663be522e408124198a3091a0cf9d9"/><file name="SuggestAdapter.php" hash="3323d92b9a9dcb80a0587fab203c5a73"/><file name="TagCloudAdapter.php" hash="cd4ebb2581682d478d71ba1aeb62e01e"/></dir></dir><dir name="FACTFinderCustom"><file name="Configuration.php" hash="96b16f73d80f74ee0a24d39bc81ac321"/></dir></dir></target><target name="magecommunity"><dir><dir name="Flagbit"><dir name="FactFinder"><dir name="Block"><file name="Layer.php" hash="cdb69ca287a7332f63c9fd32746d8896"/><file name="Scic.php" hash="9ba6aa43204d0aae206d9f24f09aecfc"/><file name="TagCloud.php" hash="664c18eceaa82779a60b6eb1694cdfca"/><dir name="Adminhtml"><file name="Cockpit.php" hash="7f5f3e8521f002c8c7b5a2d5f72cf5e1"/><dir name="Form"><dir name="Field"><file name="Attribute.php" hash="2e60d7473163fa523f10b2d0c441fe24"/><file name="Attributes.php" hash="cbaf317aa5ce4417cfcd02a6c4f36486"/></dir></dir></dir><dir name="Campaign"><file name="Advisory.php" hash="9eb34869abbc7e4ba4fe3825835793eb"/><file name="Feedback.php" hash="ffb877d1e9cb5e7fb7b9d5731a8ace56"/><dir name="Cart"><file name="Advisory.php" hash="9861e5ff8bb10fdec38d17bc9f61090a"/><file name="Feedback.php" hash="aa9239e92f528ff6b216942194f36776"/></dir><dir name="Product"><file name="Advisory.php" hash="d4736ab3436e7966c37b393a339110ca"/><file name="Feedback.php" hash="7843ed6669b7e6bdd92934b3aeb2fd41"/></dir></dir><dir name="Cart"><file name="Crosssell.php" hash="73e43a5c9048a1d139910dc7a2199952"/></dir><dir name="Filter"><file name="Slider.php" hash="159d3e1b403625dbbb970e5e7ada4ec7"/></dir><dir name="Layer"><file name="Abstract.php" hash="f53a3e2d6ce0da4afee58b4ea806a342"/></dir><dir name="Product"><dir name="List"><file name="Crosssell.php" hash="8b6936aa661cd77a1866da3bc2a40939"/><file name="Upsell.php" hash="1dc055dc3cbac045910704181be1453b"/></dir></dir><dir name="XmlConnect"><dir name="Catalog"><file name="Search.php" hash="662f7b0df8d21626bf6193906aed5162"/><dir name="Product"><file name="List.php" hash="79103c53bbaa03f02ed8a78554dcc791"/></dir><dir name="Search"><file name="Suggest.php" hash="5c7ef36939885a14ee0644cbb91a945d"/></dir></dir></dir></dir><dir name="controllers"><file name="ExportController.php" hash="01a45ff00a9b5a95ae397fd555507592"/><file name="ProxyController.php" hash="587f159bad384600c724568a61546b66"/><dir name="Adminhtml"><dir name="Factfinder"><file name="CockpitController.php" hash="4c8665feaf14c38e6ba2384db496c95a"/></dir></dir></dir><dir name="documentation"><file name="Installation_FACT-Finder_Magento_de.pdf" hash="b4711171c625caaa8996a6a09e0eaaae"/><file name="Installation_FACT-Finder_Magento_en.pdf" hash="d4bef19418ee33a223fbda2d45cca686"/></dir><dir name="etc"><file name="adminhtml.xml" hash="1165a0fecfaa31f2aa4a882d1d8bc033"/><file name="config.xml" hash="034774e583bc252138ad97ed2d1b3033"/><file name="system.xml" hash="dfe5072b02f952bfda82963683ec0b20"/></dir><dir name="Helper"><file name="Backend.php" hash="57771ad274e7e0ea63b9a934b3757f04"/><file name="Data.php" hash="afede9edaf2bcfbc93a4049eee5be89e"/><file name="Debug.php" hash="0e35720a3c3fea9d4d2feece970e6ab0"/><file name="Search.php" hash="8e043ec61152a91d78361e73d7679f9d"/></dir><dir name="Model"><file name="Adapter.php" hash="f0b105f413f6d4870f3a7f498877d983"/><file name="Layer.php" hash="9da16c44259b4a31d73f63d87787ff11"/><file name="Observer.php" hash="f08ea0a8ac7928166329c00be8e2ccad"/><file name="Processor.php" hash="1a48223d1208215013f314a5439b3028"/><dir name="Export"><file name="Price.php" hash="5561605bf639385c211f339f0c752a0f"/><file name="Product.php" hash="f5c83235446394a7ccac8af132e1037d"/><file name="Stock.php" hash="28e819f8f317957a70a7d4d318e04791"/></dir><dir name="Layer"><file name="Abstract.php" hash="0a0505e719ca55320da35c7510b82d3a"/><dir name="Filter"><file name="Item.php" hash="28e42624d764342dae6cb09a1b29b7b8"/><dir name="Attribute"><file name="Abstract.php" hash="2ad710352f1803d15ba056cd93d519f1"/><file name="Catalog.php" hash="f6dce5ea64da9dfb3458ae9ff4b58a7b"/><file name="Catalogsearch.php" hash="75536576aaaa0186f166550ee746ae04"/></dir></dir></dir><dir name="Mysql4"><dir name="Campaign"><dir name="Pushedproducts"><file name="Collection.php" hash="c966a40c7569b70cef93e47781b95190"/></dir></dir><dir name="Product"><dir name="Attribute"><file name="Collection.php" hash="d9000f3e9c709fa63313b15f34803d74"/></dir><dir name="Recommendation"><file name="Collection.php" hash="fdb6f35fa1cca09aa405bc5cd0c68601"/></dir></dir><dir name="Scic"><file name="Queue.php" hash="a1521000a1a10df8e6b580f33d06cf23"/><dir name="Queue"><file name="Collection.php" hash="5f6b0b6a50838929065ebd941cedce42"/></dir></dir><dir name="Search"><file name="Collection.php" hash="12356224ac22113428b38120a1a002a6"/><file name="Engine.php" hash="88a56eb3b4587d87bb1152476b64036e"/></dir></dir><dir name="Scic"><file name="Queue.php" hash="828d391339a22c15ad74ae1a2e784b41"/></dir><dir name="System"><dir name="Config"><dir name="Backend"><file name="Attributes.php" hash="8259883090dc4bca9b858d047983e736"/><file name="Enabled.php" hash="3b4d1f4b37d7ddba9768a7da6e3fc778"/></dir><dir name="Source"><file name="Authtype.php" hash="5bc0b1c745782cc51d44d56299059bcb"/><file name="Identifier.php" hash="cec45238f0e28a1bf66d10dee513c2ca"/></dir></dir></dir></dir><dir name="sql"><dir name="factfinder_setup"><file name="mysql4-install-3.2.0.php" hash="1342320595048cd96659c454381cfbb4"/><file name="mysql4-upgrade-3.2.0-3.2.1.php" hash="3d5276dfe971a6bd48aa8e2a085de004"/><file name="mysql4-upgrade-3.2.1-3.3.0.php" hash="71954ea0cf400950d23b020ff095a9ee"/></dir></dir></dir></dir></dir></target><target name="mage"><dir><dir name="js"><dir name="factfinder"><file name="jXHR.js" hash="0473a3ea88f08797737814c7ffbeba18"/><file name="scic.js" hash="10f509fb3f468a8557ca17205a361d52"/><file name="suggest.js" hash="c39230ada8f44c3d3a8c7540c0b4a8c9"/></dir></dir></dir></target></contents>
20
+ <compatible/>
21
+ <dependencies/>
22
+ </package>