SooqrSearch - Version 1.0.5

Version Notes

Incompatible changes since 1.0.4:
- Customers with custom changes to their plugin should NOT update to this new version. Please contact Sooqr support for more information.
- The Sooqr plugin now defaults to the new responsive design. This only works if your account has been upgraded to the responsive templates. Please change the setting 'Frontend version' under 'Advanced settings' to 'Version 3 (Original)'.

Changes since 1.0.4
- Support for catalog price rules.
- Better support for custom product types.
- Bugfixes for promotional prices.
- Extra options to align Sooqr to base design.
- Bugfix for selecting the correct store ID.
- Products from inactive categories are now excluded.
- Added basic logging.
- Possibility to start the generator from another Mage event.
- Setting for custom thumbnail size.
- Enable/disable categories in Sooqr feed.
- Bufixes for products with special chars.
- Thumbnail are now recreated on the background after the cache is cleared.
- Keywords are now also exported
- The SKU's for grouped products are now exported as a single string
- Stock info is now exported
- Product type is now exported
- Bugfix grouped priceses

Changes since 1.0.3.1
- Plugin now reports basic configuration settings to the mySooqr backend.

Changes since 1.0.3
- Small bugfix for new installations

Changes since 1.0.2
- New price option for Grouped products.
- Input validation for account information.

Changes since 1.0.1
- Bugfix: default field mapping was incorrect
- Images are now scaled to 120x120 pixels

Changes since 0.4.5
- First public release of SooqrSearch plugin.

Changes since 0.4.4
- Grouping configurable products into one item.

Changes since 0.4.3
- Improved support for configurable products

Changes since 0.4.2
- Bugfix: tax class was named incorrectly
- Feed is now generated for the active (of specified) store.

Changes since 0.4.1
- Added configuration option to export all custom attributes

Changes since 0.4.0
- Support for exporting all user defined attributes

Changes since 0.3.5
- Complete rebuild of the module. Custom fields can now be specified in the configuration screen.

Changes since 0.3.4
- Additional checks on attribute existence

Changes since 0.3.3
- Debugging option added

Changes since 0.3.2
- Bugfix: manufacterer field is not always available
- Changes to the visibility of configuration fields

Download this release

Release Info

Developer internetbureau Websight
Extension SooqrSearch
Version 1.0.5
Comparing to
See all releases


Code changes from version 1.0.4.4 to 1.0.5

Files changed (31) hide show
  1. app/code/community/Sooqr/Feed/Block/Adminhtml/System/Config/Form/Field/Customfieldmap.php +27 -27
  2. app/code/community/Sooqr/Feed/Block/Adminhtml/System/Config/Form/Field/Fieldmap.php +27 -27
  3. app/code/community/Sooqr/Feed/Helper/SimpleXml.php +1 -1
  4. app/code/community/Sooqr/Feed/Helper/Tax.php +3 -3
  5. app/code/community/Sooqr/Feed/Model/Config.php +116 -64
  6. app/code/community/Sooqr/Feed/Model/Generator.php +894 -707
  7. app/code/community/Sooqr/Feed/Model/Map/Page/Abstract.php +27 -0
  8. app/code/community/Sooqr/Feed/Model/Map/Product/Abstract.php +847 -818
  9. app/code/community/Sooqr/Feed/Model/Map/Product/Associated.php +234 -234
  10. app/code/community/Sooqr/Feed/Model/Map/Product/Bundle.php +40 -40
  11. app/code/community/Sooqr/Feed/Model/Map/Product/Configurable.php +288 -288
  12. app/code/community/Sooqr/Feed/Model/Map/Product/Grouped.php +70 -65
  13. app/code/community/Sooqr/Feed/Model/Source/Producttypes.php +6 -6
  14. app/code/community/Sooqr/Feed/Model/System/Config/Backend/Serialized/Customfieldmap.php +20 -19
  15. app/code/community/Sooqr/Feed/Model/System/Config/Backend/Serialized/Fieldmap.php +15 -15
  16. app/code/community/Sooqr/Feed/Model/Tools.php +541 -277
  17. app/code/community/Sooqr/Feed/controllers/IndexController.php +3 -3
  18. app/code/community/Sooqr/Feed/etc/config.xml +3 -1
  19. app/code/community/Sooqr/Feed/etc/system.xml +5 -1
  20. app/code/community/Sooqr/Feed/scripts/generate_sooqr_feed.php +2 -2
  21. app/code/community/Sooqr/Feed/scripts/generate_sooqr_feed2.php +66 -0
  22. app/code/community/Sooqr/Feed/scripts/resize_images.php +25 -0
  23. app/code/community/Sooqr/Search/Block/Adminhtml/System/Config/Fieldset/Info.php +17 -15
  24. app/code/community/Sooqr/Search/Block/Form.php +97 -0
  25. app/code/community/Sooqr/Search/Model/Accountid.php +8 -1
  26. app/code/community/Sooqr/Search/Model/Source/Versions.php +35 -0
  27. app/code/community/Sooqr/Search/etc/config.xml +7 -1
  28. app/code/community/Sooqr/Search/etc/system.xml +58 -4
  29. app/design/frontend/default/default/template/catalogsearch/form.mini.phtml +23 -15
  30. app/etc/modules/Sooqr_All.xml +25 -0
  31. package.xml +26 -8
app/code/community/Sooqr/Feed/Block/Adminhtml/System/Config/Form/Field/Customfieldmap.php CHANGED
@@ -35,7 +35,7 @@
35
 
36
  class Sooqr_Feed_Block_Adminhtml_System_Config_Form_Field_Customfieldmap extends Mage_Adminhtml_Block_System_Config_Form_Field_Array_Abstract
37
  {
38
- public function __construct()
39
  {
40
  $this->addColumn('attribute', array(
41
  'label' => Mage::helper('adminhtml')->__('Product Attribute'),
@@ -56,20 +56,20 @@ class Sooqr_Feed_Block_Adminhtml_System_Config_Form_Field_Customfieldmap extends
56
  */
57
  protected function getProductAttributesCodes()
58
  {
59
- $storeId = null;
60
- if (($storeCode = $this->getRequest()->getParam('store')) != '')
61
- {
62
- $storeId = Mage::app()->getStore($storeCode)->getStoreId();
63
- }
64
-
65
- $attributeCodes = Mage::getSingleton('feed/config')->getProductAttributesCodes($storeId);
66
-
67
- $result = array();
68
- foreach ($attributeCodes as $k => $v)
69
- {
70
- $result[$k] = addslashes($v);
71
- }
72
- return $result;
73
  }
74
 
75
  /**
@@ -104,27 +104,27 @@ class Sooqr_Feed_Block_Adminhtml_System_Config_Form_Field_Customfieldmap extends
104
  $optGroup = false;
105
  foreach ($this->getProductAttributesCodes() as $value => $label)
106
  {
107
- if (!$optGroup
108
- && strpos($label, '(') !== false)
109
- {
110
- $html .= '<optgroup label="'.$this->__('Attributes').'"></optgroup>';
111
- $optGroup = true;
112
- }
113
- $html .= '<option label="'.$label.'" value="'.$value.'">'.$label.'</option>';
114
  }
115
  $html .= '</select>';
116
  }
117
  else
118
  {
119
- $html .= '<input type="hidden" name="' . $inputName . '" value="#{' . $columnName . '}" />';
120
- $html .= '#{label}';
121
  }
122
-
123
- return $html;
124
  }
125
 
126
  public function hasDefaultValueBehaviour()
127
  {
128
- return false;
129
  }
130
  }
35
 
36
  class Sooqr_Feed_Block_Adminhtml_System_Config_Form_Field_Customfieldmap extends Mage_Adminhtml_Block_System_Config_Form_Field_Array_Abstract
37
  {
38
+ public function __construct()
39
  {
40
  $this->addColumn('attribute', array(
41
  'label' => Mage::helper('adminhtml')->__('Product Attribute'),
56
  */
57
  protected function getProductAttributesCodes()
58
  {
59
+ $storeId = null;
60
+ if (($storeCode = $this->getRequest()->getParam('store')) != '')
61
+ {
62
+ $storeId = Mage::app()->getStore($storeCode)->getStoreId();
63
+ }
64
+
65
+ $attributeCodes = Mage::getSingleton('feed/config')->getProductAttributesCodes($storeId);
66
+
67
+ $result = array();
68
+ foreach ($attributeCodes as $k => $v)
69
+ {
70
+ $result[$k] = addslashes($v);
71
+ }
72
+ return $result;
73
  }
74
 
75
  /**
104
  $optGroup = false;
105
  foreach ($this->getProductAttributesCodes() as $value => $label)
106
  {
107
+ if (!$optGroup
108
+ && strpos($label, '(') !== false)
109
+ {
110
+ $html .= '<optgroup label="'.$this->__('Attributes').'"></optgroup>';
111
+ $optGroup = true;
112
+ }
113
+ $html .= '<option label="'.$label.'" value="'.$value.'">'.$label.'</option>';
114
  }
115
  $html .= '</select>';
116
  }
117
  else
118
  {
119
+ $html .= '<input type="hidden" name="' . $inputName . '" value="#{' . $columnName . '}" />';
120
+ $html .= '#{label}';
121
  }
122
+
123
+ return $html;
124
  }
125
 
126
  public function hasDefaultValueBehaviour()
127
  {
128
+ return false;
129
  }
130
  }
app/code/community/Sooqr/Feed/Block/Adminhtml/System/Config/Form/Field/Fieldmap.php CHANGED
@@ -35,7 +35,7 @@
35
 
36
  class Sooqr_Feed_Block_Adminhtml_System_Config_Form_Field_Fieldmap extends Mage_Adminhtml_Block_System_Config_Form_Field_Array_Abstract
37
  {
38
- public function __construct()
39
  {
40
  $this->addColumn('field', array(
41
  'label' => Mage::helper('adminhtml')->__('Sooqr Feed Field'),
@@ -60,20 +60,20 @@ class Sooqr_Feed_Block_Adminhtml_System_Config_Form_Field_Fieldmap extends Mage_
60
  */
61
  protected function getProductAttributesCodes()
62
  {
63
- $storeId = null;
64
- if (($storeCode = $this->getRequest()->getParam('store')) != '')
65
- {
66
- $storeId = Mage::app()->getStore($storeCode)->getStoreId();
67
- }
68
-
69
- $attributeCodes = Mage::getSingleton('feed/config')->getProductAttributesCodes($storeId);
70
-
71
- $result = array();
72
- foreach ($attributeCodes as $k => $v)
73
- {
74
- $result[$k] = addslashes($v);
75
- }
76
- return $result;
77
  }
78
 
79
  /**
@@ -108,27 +108,27 @@ class Sooqr_Feed_Block_Adminhtml_System_Config_Form_Field_Fieldmap extends Mage_
108
  $optGroup = false;
109
  foreach ($this->getProductAttributesCodes() as $value => $label)
110
  {
111
- if (!$optGroup
112
- && strpos($label, '(') !== false)
113
- {
114
- $html .= '<optgroup label="'.$this->__('Attributes').'"></optgroup>';
115
- $optGroup = true;
116
- }
117
- $html .= '<option label="'.$label.'" value="'.$value.'">'.$label.'</option>';
118
  }
119
  $html .= '</select>';
120
  }
121
  else
122
  {
123
- $html .= '<input type="hidden" name="' . $inputName . '" value="#{' . $columnName . '}" />';
124
- $html .= '#{label}';
125
  }
126
-
127
- return $html;
128
  }
129
 
130
  public function hasDefaultValueBehaviour()
131
  {
132
- return false;
133
  }
134
  }
35
 
36
  class Sooqr_Feed_Block_Adminhtml_System_Config_Form_Field_Fieldmap extends Mage_Adminhtml_Block_System_Config_Form_Field_Array_Abstract
37
  {
38
+ public function __construct()
39
  {
40
  $this->addColumn('field', array(
41
  'label' => Mage::helper('adminhtml')->__('Sooqr Feed Field'),
60
  */
61
  protected function getProductAttributesCodes()
62
  {
63
+ $storeId = null;
64
+ if (($storeCode = $this->getRequest()->getParam('store')) != '')
65
+ {
66
+ $storeId = Mage::app()->getStore($storeCode)->getStoreId();
67
+ }
68
+
69
+ $attributeCodes = Mage::getSingleton('feed/config')->getProductAttributesCodes($storeId);
70
+
71
+ $result = array();
72
+ foreach ($attributeCodes as $k => $v)
73
+ {
74
+ $result[$k] = addslashes($v);
75
+ }
76
+ return $result;
77
  }
78
 
79
  /**
108
  $optGroup = false;
109
  foreach ($this->getProductAttributesCodes() as $value => $label)
110
  {
111
+ if (!$optGroup
112
+ && strpos($label, '(') !== false)
113
+ {
114
+ $html .= '<optgroup label="'.$this->__('Attributes').'"></optgroup>';
115
+ $optGroup = true;
116
+ }
117
+ $html .= '<option label="'.$label.'" value="'.$value.'">'.$label.'</option>';
118
  }
119
  $html .= '</select>';
120
  }
121
  else
122
  {
123
+ $html .= '<input type="hidden" name="' . $inputName . '" value="#{' . $columnName . '}" />';
124
+ $html .= '#{label}';
125
  }
126
+
127
+ return $html;
128
  }
129
 
130
  public function hasDefaultValueBehaviour()
131
  {
132
+ return false;
133
  }
134
  }
app/code/community/Sooqr/Feed/Helper/SimpleXml.php CHANGED
@@ -8,5 +8,5 @@ class Sooqr_Feed_Helper_SimpleXml extends SimpleXMLElement
8
  $node = dom_import_simplexml($node);
9
  $nodeOwner = $node->ownerDocument;
10
  $node->appendChild($nodeOwner->createCDATASection($cdata_text));
11
- }
12
  }
8
  $node = dom_import_simplexml($node);
9
  $nodeOwner = $node->ownerDocument;
10
  $node->appendChild($nodeOwner->createCDATASection($cdata_text));
11
+ }
12
  }
app/code/community/Sooqr/Feed/Helper/Tax.php CHANGED
@@ -17,9 +17,9 @@
17
 
18
  class Sooqr_Feed_Helper_Tax extends Mage_Tax_Helper_Data
19
  {
20
- /**
21
- * Overrides default to always true.
22
- *
23
  * Check if necessary do product price conversion
24
  * If it necessary will be returned conversion type (minus or plus)
25
  *
17
 
18
  class Sooqr_Feed_Helper_Tax extends Mage_Tax_Helper_Data
19
  {
20
+ /**
21
+ * Overrides default to always true.
22
+ *
23
  * Check if necessary do product price conversion
24
  * If it necessary will be returned conversion type (minus or plus)
25
  *
app/code/community/Sooqr/Feed/Model/Config.php CHANGED
@@ -1,32 +1,32 @@
1
- <?php
2
-
3
- class Sooqr_Feed_Model_Config extends Mage_Core_Model_Config_Data
4
- {
5
- protected $_product_attributes_codes = null;
6
- protected $_product_directives = null;
7
- protected $_directives = null;
8
-
9
- const BASE_CONFIG_PATH = 'sooqr';
10
-
11
- public function __construct()
12
- {
13
- }
14
-
15
  public function getConfigVar($key, $storeId = null, $section = 'feed')
16
- {
17
  switch ($key)
18
  {
19
  case 'field_map':
20
  $result = $this->getConfigVarFieldMap($key, $storeId, $section);
21
- break;
22
 
23
  default:
24
  $result = Mage::getStoreConfig(self::BASE_CONFIG_PATH.'/'.$section.'/'.$key, $storeId);
25
- }
26
-
27
  return $result;
28
- }
29
-
30
  /**
31
  * Shortcut to config values with frontend type multiselect.
32
  *
@@ -36,28 +36,28 @@ class Sooqr_Feed_Model_Config extends Mage_Core_Model_Config_Data
36
  * @return mixed
37
  */
38
  public function getConfigVarFieldMap($key, $storeId = null, $section = 'feed')
39
- {
40
- $data = Mage::getStoreConfig(self::BASE_CONFIG_PATH.'/'.$section.'/'.$key, $storeId);
41
  if (empty($data))
42
  {
43
  $data = $this->convertDefaultFieldMap($storeId);
44
- }
45
 
46
  return $data;
47
- }
48
-
49
  public function getMultipleSelectVar($key, $storeId = null, $section = 'feed')
50
  {
51
  $str = $this->getConfigVar($key, $storeId, $section);
52
  $values = array();
53
- if (!empty($str))
54
  {
55
- $values = explode(',', $str);
56
- }
57
 
58
  return array_filter($values);
59
- }
60
-
61
  /**
62
  * Converts config var default_field_map to format of backend type serialized array.
63
  *
@@ -67,19 +67,19 @@ class Sooqr_Feed_Model_Config extends Mage_Core_Model_Config_Data
67
  public function convertDefaultFieldMap($storeId = null)
68
  {
69
  $result = array();
70
- $defaultMapping = $this->getConfigVar('default_field_map', $storeId);
71
  foreach ($defaultMapping as $field => $arr)
72
  {
73
- $result[] = array(
74
  'label' => $arr['label'],
75
  'attribute' => $arr['attribute'],
76
  'field' => $field,
77
  );
78
- }
79
 
80
  return $result;
81
- }
82
-
83
  /**
84
  * Crates array of attributes and directives for dropdowns.
85
  * [code] => [label]
@@ -89,9 +89,9 @@ class Sooqr_Feed_Model_Config extends Mage_Core_Model_Config_Data
89
  * @return array
90
  */
91
  public function getProductAttributesCodes($storeId = null, $withDirectives = true)
92
- {
93
  $moduleConfig = Mage::getSingleton('feed/config');
94
- $excludeAttributes = $moduleConfig->getMultipleSelectVar('exclude_attributes');
95
 
96
  if (is_null($this->_product_attributes_codes))
97
  {
@@ -99,24 +99,24 @@ class Sooqr_Feed_Model_Config extends Mage_Core_Model_Config_Data
99
 
100
  $config = Mage::getModel('eav/config');
101
  $baseObject = new Varien_Object(array('store_id' => $storeId));
102
- $attributesCodes = $config->getEntityAttributeCodes('catalog_product', $baseObject);
103
  foreach ($attributesCodes as $attributeCode)
104
- {
105
- if (array_search($attributeCode, $excludeAttributes) !== false)
106
  {
107
- continue;
108
  }
109
- $attribute = $config->getAttribute('catalog_product', $attributeCode);
110
- if ($attribute !== false
111
  && $attribute->getAttributeId() > 0)
112
- {
113
  $this->_product_attributes_codes[$attribute->getAttributeCode()] = addslashes($attribute->getFrontend()->getLabel().' ('.$attribute->getAttributeCode().')');
114
  }
115
  }
116
  asort($this->_product_attributes_codes);
117
- }
118
-
119
- if ($withDirectives === true
120
  && is_null($this->_product_directives))
121
  {
122
  $this->_product_directives = array();
@@ -132,31 +132,83 @@ class Sooqr_Feed_Model_Config extends Mage_Core_Model_Config_Data
132
  $result = array();
133
  if ($withDirectives === true)
134
  {
135
- $result = array_merge(
136
- $this->_product_directives,
137
- $this->_product_attributes_codes
138
  );
139
  }
140
  else
141
  {
142
  $result = $this->_product_attributes_codes;
143
- }
144
 
145
  return $result;
146
- }
147
-
148
- /**
149
- * Checks if the selected attribute is actualy a directive
150
- *
151
- * @param string $code
152
- * @return boolean true is the code is a directive, false otherwise
153
- */
154
  public function isDirective($code, $storeId = null)
155
- {
156
- if (is_null($this->_directives))
157
  {
158
- $this->_directives = $this->getConfigVar('directives', $storeId);
159
- }
160
- return isset($this->_directives[$code]);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
161
  }
162
  }
1
+ <?php
2
+
3
+ class Sooqr_Feed_Model_Config extends Mage_Core_Model_Config_Data
4
+ {
5
+ protected $_product_attributes_codes = null;
6
+ protected $_product_directives = null;
7
+ protected $_directives = null;
8
+
9
+ const BASE_CONFIG_PATH = 'sooqr';
10
+
11
+ public function __construct()
12
+ {
13
+ }
14
+
15
  public function getConfigVar($key, $storeId = null, $section = 'feed')
16
+ {
17
  switch ($key)
18
  {
19
  case 'field_map':
20
  $result = $this->getConfigVarFieldMap($key, $storeId, $section);
21
+ break;
22
 
23
  default:
24
  $result = Mage::getStoreConfig(self::BASE_CONFIG_PATH.'/'.$section.'/'.$key, $storeId);
25
+ }
26
+
27
  return $result;
28
+ }
29
+
30
  /**
31
  * Shortcut to config values with frontend type multiselect.
32
  *
36
  * @return mixed
37
  */
38
  public function getConfigVarFieldMap($key, $storeId = null, $section = 'feed')
39
+ {
40
+ $data = Mage::getStoreConfig(self::BASE_CONFIG_PATH.'/'.$section.'/'.$key, $storeId);
41
  if (empty($data))
42
  {
43
  $data = $this->convertDefaultFieldMap($storeId);
44
+ }
45
 
46
  return $data;
47
+ }
48
+
49
  public function getMultipleSelectVar($key, $storeId = null, $section = 'feed')
50
  {
51
  $str = $this->getConfigVar($key, $storeId, $section);
52
  $values = array();
53
+ if (!empty($str))
54
  {
55
+ $values = explode(',', $str);
56
+ }
57
 
58
  return array_filter($values);
59
+ }
60
+
61
  /**
62
  * Converts config var default_field_map to format of backend type serialized array.
63
  *
67
  public function convertDefaultFieldMap($storeId = null)
68
  {
69
  $result = array();
70
+ $defaultMapping = $this->getConfigVar('default_field_map', $storeId);
71
  foreach ($defaultMapping as $field => $arr)
72
  {
73
+ $result[] = array(
74
  'label' => $arr['label'],
75
  'attribute' => $arr['attribute'],
76
  'field' => $field,
77
  );
78
+ }
79
 
80
  return $result;
81
+ }
82
+
83
  /**
84
  * Crates array of attributes and directives for dropdowns.
85
  * [code] => [label]
89
  * @return array
90
  */
91
  public function getProductAttributesCodes($storeId = null, $withDirectives = true)
92
+ {
93
  $moduleConfig = Mage::getSingleton('feed/config');
94
+ $excludeAttributes = $moduleConfig->getMultipleSelectVar('exclude_attributes');
95
 
96
  if (is_null($this->_product_attributes_codes))
97
  {
99
 
100
  $config = Mage::getModel('eav/config');
101
  $baseObject = new Varien_Object(array('store_id' => $storeId));
102
+ $attributesCodes = $config->getEntityAttributeCodes('catalog_product', $baseObject);
103
  foreach ($attributesCodes as $attributeCode)
104
+ {
105
+ if (array_search($attributeCode, $excludeAttributes) !== false)
106
  {
107
+ continue;
108
  }
109
+ $attribute = $config->getAttribute('catalog_product', $attributeCode);
110
+ if ($attribute !== false
111
  && $attribute->getAttributeId() > 0)
112
+ {
113
  $this->_product_attributes_codes[$attribute->getAttributeCode()] = addslashes($attribute->getFrontend()->getLabel().' ('.$attribute->getAttributeCode().')');
114
  }
115
  }
116
  asort($this->_product_attributes_codes);
117
+ }
118
+
119
+ if ($withDirectives === true
120
  && is_null($this->_product_directives))
121
  {
122
  $this->_product_directives = array();
132
  $result = array();
133
  if ($withDirectives === true)
134
  {
135
+ $result = array_merge(
136
+ $this->_product_directives,
137
+ $this->_product_attributes_codes
138
  );
139
  }
140
  else
141
  {
142
  $result = $this->_product_attributes_codes;
143
+ }
144
 
145
  return $result;
146
+ }
147
+
148
+ /**
149
+ * Checks if the selected attribute is actualy a directive
150
+ *
151
+ * @param string $code
152
+ * @return boolean true is the code is a directive, false otherwise
153
+ */
154
  public function isDirective($code, $storeId = null)
155
+ {
156
+ if (is_null($this->_directives))
157
  {
158
+ $this->_directives = $this->getConfigVar('directives', $storeId);
159
+ }
160
+ return isset($this->_directives[$code]);
161
+ }
162
+
163
+ /**
164
+ *
165
+ * @param array $info like the one in Mage::getVersionInfo()
166
+ * @param string $operator Operators: >= > <= < != ==
167
+ */
168
+ public function compareMagentoVersion($info, $operator = null)
169
+ {
170
+ $ret = false;
171
+ if (!is_array($info))
172
+ return false;
173
+ if (is_null($operator))
174
+ $operator = ">=";
175
+ $cinfo = Mage::getVersionInfo();
176
+ $keys = array('major', 'minor', 'revision', 'patch');
177
+ $c = $cv = 0;
178
+ $i = 4;
179
+ foreach ($keys as $key) {
180
+ $cv += intval($cinfo[$key]) * pow(10, --$i);
181
+ }
182
+ $i = 4;
183
+ foreach ($keys as $key) {
184
+ if (!isset($info[$key]))
185
+ return false;
186
+ $c += intval($info[$key]) * pow(10, --$i);
187
+ }
188
+ switch ($operator) {
189
+ case '>=':
190
+ if ($cv >= $c) $ret = true;
191
+ break;
192
+ case '>':
193
+ if ($cv > $c) $ret = true;
194
+ break;
195
+ case '<':
196
+ if ($cv <= $c) $ret = true;
197
+ break;
198
+ case '<=':
199
+ if ($cv < $c) $ret = true;
200
+ break;
201
+ case '!=':
202
+ if ($cv != $c) $ret = true;
203
+ break;
204
+ case '==':
205
+ if ($cv == $c) $ret = true;
206
+ break;
207
+
208
+ default:
209
+ if ($cv >= $c) $ret = true;
210
+ }
211
+
212
+ return $ret;
213
  }
214
  }
app/code/community/Sooqr/Feed/Model/Generator.php CHANGED
@@ -1,717 +1,904 @@
1
- <?php
2
-
3
- class Sooqr_Feed_Model_Generator extends Varien_Object
4
- {
5
- const THUMBNAIL_WIDTH = 120;
6
- const THUMBNAIL_HEIGHT = 120;
7
-
8
- private $sProductElement = 'item';
9
- private $oProductModel;
10
- private $aBadChars = array('"',"\r\n","\n","\r","\t");
11
- private $aReplaceChars = array(""," "," "," ","");
12
-
13
- private $oTagModel = null;
14
-
15
- private $_oXmlWriter;
16
- private $_oProducts;
17
- private $_iProductCount;
18
- private $_iBatchSize;
19
- private $_oCurrentStore;
20
- private $_iCurrentStoreId;
21
- private $_iCurrentWebsiteId;
22
- private $_sCurrentStoreCode;
23
- private $_sCurrentStoreSuffix;
24
- private $_oCollection;
25
- private $_aFieldMap = null;
26
- private $_aAttributes = null;
27
-
28
- private $aCDataNodes = array(
29
- 'description', 'link', 'image_link',
30
- );
31
-
32
- private $_aNamespaces = array(
33
- 'g' => 'http://base.google.com/ns/1.0',
34
- 'sqr' => 'http://base.sooqr.com/ns/1.0',
35
- );
36
-
37
- private $_aFieldNamespaces = array(
38
- 'id' => 'g',
39
- 'price' => 'g',
40
- 'normal_price' => 'sqr',
41
- 'mpn' => 'g',
42
- 'brand' => 'g',
43
- 'magento_store' => 'sqr',
44
- 'attribute_set' => 'sqr',
45
- 'category0' => 'sqr',
46
- 'category1' => 'sqr',
47
- 'category2' => 'sqr',
48
- 'category3' => 'sqr',
49
- );
50
-
51
- public function run()
52
- {
53
- // Enabled browser debugging
54
- if ($this->getConfigVar('debugging', null, 'advanced') == 1
55
- || $this->getDebug() == true)
56
- {
57
- error_reporting(E_ALL);
58
- ini_set('display_errors', 'On');
59
- }
60
-
61
- if ($this->getConfigVar('enabled') == 1)
62
- {
63
- $this->_iBatchSize = $this->getConfigVar('batch_size');
64
-
65
- // Initialize the current store settings
66
- if (!$this->hasData('store_code'))
67
- {
68
- $this->setData('store_code', Mage_Core_Model_Store::DEFAULT_CODE);
69
- }
70
-
71
- // Try to load the specified store code
72
- try
73
- {
74
- $this->_oCurrentStore = Mage::app()->getStore($this->getData('store_code'));
75
- }
76
- catch (Exception $e)
77
- {
78
- $e->setMessage(sprintf('Store with code \'%s\' doesn\'t exists.', $this->getData('store_code')));
79
- $this->_stopOnException($e);
80
- }
81
-
82
- $this->_iCurrentStoreId = $this->getData('store_id');
83
- $this->_iCurrentStoreId = $this->_oCurrentStore->getStoreId();
84
- $this->_sCurrentStoreCode = $this->_oCurrentStore->getCode();
85
- $this->_iCurrentWebsiteId = $this->_oCurrentStore->getWebsiteId();
86
-
87
- // For multiple store views, use prefixes for the product ID's
88
- if ($this->_sCurrentStoreCode == 'default')
89
- {
90
- $this->_sCurrentStoreSuffix = '';
91
- }
92
- else
93
- {
94
- $this->_sCurrentStoreSuffix = '_'.$this->_oCurrentStore->getCode();
95
- }
96
-
97
- // Check if we are running the export from the command line script
98
- if ($this->getCliMode())
99
- {
100
- // Check if we should process in background
101
- if ($this->getConfigVar('background_mode') == 1)
102
- {
103
- $this->_generateFeed();
104
- }
105
- else
106
- {
107
- throw new Exception('This script should only be run when background_mode is enabled in the Sooqr Feed configuration.');
108
- }
109
- }
110
- else
111
- {
112
- // Check if we should generate the feed on the fly
113
- if ($this->getConfigVar('background_mode') == 0
114
- || $this->getReload())
115
- {
116
- $this->_generateFeed();
117
- }
118
-
119
- if (!$this->_checkFeedPath())
120
- {
121
- header('HTTP/1.1 404 Feed does not exist', true, 404);
122
- echo 'The requested datafeed is currently not available.';
123
- exit;
124
- }
125
- else
126
- {
127
- // Output the generated feed to the browser
128
- $this->_streamCacheFileToBrowser();
129
- }
130
- }
131
- }
132
- }
133
-
134
- /**
135
- * @return RocketWeb_GoogleBaseFeedGenerator_Model_Generator
136
- */
137
- protected function _loadAdditionalAttributes()
138
- {
139
- $codes = array('status');
140
- $product = Mage::getModel('catalog/product')->setStoreId($this->getData('store_id'));
141
- foreach ($codes as $attribute_code) {
142
- $attribute = $product->getResource()->getAttribute($attribute_code);
143
- $this->_aAttributes[$attribute->getAttributeCode()] = $attribute;
144
- }
145
-
146
- return $this;
147
- }
148
-
149
- private function _generateFeed()
150
- {
151
- $this->_loadAdditionalAttributes();
152
-
153
- $this->_initFeed();
154
-
155
- // Load the tag model for processing product tags
156
- $this->oTagModel = Mage::getModel('tag/tag');
157
-
158
- $this->_initProducts($this->_oCurrentStore);
159
-
160
- $exportLimit = !is_null($this->getLimit()) ? $this->getLimit() : $this->_iProductCount;
161
-
162
- for ($iProductOffset = 0; $iProductOffset < $exportLimit; $iProductOffset += $this->_iBatchSize)
163
- {
164
- $batchSize = min($exportLimit - $iProductOffset, $this->_iBatchSize);
165
- $collection = $this->_getProductCollection($this->_oCurrentStore, $iProductOffset,
166
- $batchSize);
167
-
168
- Mage::getSingleton('core/resource_iterator')->walk($collection->getSelect(),
169
- array(array($this, 'addProductToFeed')));
170
-
171
- // Flushes all processed products to disk
172
- $this->_flushFeed();
173
- }
174
-
175
- $this->_closeFeed();
176
- }
177
-
178
- public function getConfig()
179
- {
180
- return Mage::getSingleton('feed/config');
181
- }
182
-
183
- public function getConfigVar($key, $storeId = null, $section = 'feed')
184
- {
185
- return $this->getConfig()->getConfigVar($key, $storeId, $section);
186
- }
187
-
188
- /**
189
- * Initialises the basic feed object and flushes this information to disk
190
- *
191
- */
192
- private function _initFeed()
193
- {
194
- $this->_oXmlWriter = new XMLWriter();
195
- $this->_oXmlWriter->openMemory();
196
- $this->_oXmlWriter->startDocument('1.0', 'UTF-8');
197
-
198
- // Output the parent rss tag
199
- $this->_oXmlWriter->startElement('rss');
200
- $this->_oXmlWriter->writeAttribute('version', '2.0');
201
-
202
- foreach ($this->_aNamespaces as $prefix => $uri)
203
- {
204
- $this->_oXmlWriter->writeAttributeNs('xmlns', $prefix, null, $uri);
205
- }
206
-
207
- $this->_oXmlWriter->startElement('channel');
208
- $this->_oXmlWriter->writeElement('title', 'Product feed');
209
- $this->_oXmlWriter->startElement('link');
210
- $this->_oXmlWriter->writeCData(Mage::getBaseUrl().ltrim($_SERVER['REQUEST_URI'], '/'));
211
- $this->_oXmlWriter->endElement();
212
- $this->_oXmlWriter->writeElement('pubDate', strftime('%a, %d %b %Y %H:%M:%S %Z'));
213
- $this->_oXmlWriter->writeElement('generator', 'MagentoSooqr/'.Mage::getConfig()->getModuleConfig("Sooqr_Feed")->version);
214
- $this->_oXmlWriter->writeElement('description', 'Magento Product feed for Sooqr');
215
-
216
- // Flush the current contents to disk
217
- if (file_put_contents($this->_getFeedPath(true), $this->_oXmlWriter->flush()) === false)
218
- {
219
- throw new Exception(sprintf('Cannot write to temporary feed file: %s', $this->_getFeedPath(true)));
220
- }
221
- }
222
-
223
- /**
224
- * Flushes all the products from memory to disk
225
- */
226
- private function _flushFeed()
227
- {
228
- file_put_contents($this->_getFeedPath(true), $this->_oXmlWriter->flush(true), FILE_APPEND);
229
- }
230
-
231
- /**
232
- * Close the feed tags and write the last parts to disk
233
- *
234
- */
235
- private function _closeFeed()
236
- {
237
- $this->_oXmlWriter->endElement(); // Channel
238
- $this->_oXmlWriter->endElement(); // RSS
239
- $this->_oXmlWriter->endDocument();
240
-
241
- $this->_flushFeed();
242
-
243
- // Move the completed feed to the actual cached version
244
- if (!rename($this->_getFeedPath(true), $this->_getFeedPath()))
245
- {
246
- throw new Exception(sprintf('Cannot (over)write feed file cache: %s', $this->_getFeedPath()));
247
- }
248
- }
249
-
250
- /**
251
- * Retrieves a set of products from the Magento system.
252
- *
253
- * @param Mage_Core_Model_Store $oStore reference to the active store object
254
- */
255
- private function _initProducts(Mage_Core_Model_Store $oStore)
256
- {
257
- $collection = $this->_getProductCollection($oStore);
258
- $this->_iProductCount = $collection->getSize();;
259
- }
260
-
261
- /**
262
- * Adds a product to the XML feed
263
- *
264
- * @param integer $iProduct
265
- */
266
- public function addProductToFeed($args)
267
- {
268
- $row = $args['row'];
269
- $parentEntityId = null;
270
-
271
- // Initialize the mapping for this product type
272
- if (is_null($oProductMap = $this->_getProductMapModel($row['type_id'], array())))
273
- {
274
- return false;
275
- }
276
-
277
- // Load the current product
278
- $oProduct = Mage::getModel('catalog/product');
279
- $oProduct->setData($row);
280
- $oProduct->setStoreId($this->_iCurrentStoreId);
281
- $oProduct->getResource()->load($oProduct, $row['entity_id']);
282
-
283
- // Initialize the product map for this product type
284
- $oProductMap->setGenerator($this)
285
- ->setProduct($oProduct)
286
- ->setFieldsMap($this->_getFieldsMap())
287
- ->initialize();
288
-
289
- // Check if the product should be skipped
290
- if ($oProductMap->checkSkipSubmission()->isSkip())
291
- {
292
- return;
293
- }
294
-
295
- // Add the product to the XML output
296
- $this->_addProductToXml($oProductMap);
297
-
298
- // Clear the product map data
299
- $oProductMap->unsetData();
300
- }
301
-
302
- protected function _getFieldsMap()
303
- {
304
- // Check if we have cached this information
305
- if (!is_null($this->_aFieldMap))
306
- {
307
- return $this->_aFieldMap;
308
- }
309
-
310
- $this->_aFieldMap = array();
311
-
312
- $product = Mage::getModel('catalog/product')->setStoreId($this->getData('store_id'));
313
-
314
- $variables = array('field_map');
315
- if ($this->getConfigVar('export_all_user_attributes') != 1)
316
- {
317
- $variables[] = 'custom_field_map';
318
- }
319
-
320
- foreach ($variables as $variable)
321
- {
322
- // Load attributes used. Exclude columns with attributes that doesn't exist.
323
- $tmpMap = $configMap = $this->getConfigVar($variable);
324
- foreach ($tmpMap as $k => $mapData)
325
- {
326
- // Check if the supplied variable is a directive
327
- if (!$this->getConfig()->isDirective($mapData['attribute'], $this->getData('store_id')))
328
- {
329
- // Check if the attribute exists
330
- $attribute = $product->getResource()->getAttribute($mapData['attribute']);
331
- if ($attribute === false)
332
- {
333
- $this->log(sprintf("Field '%s' ignored, can't find attribute with code '%s'.", $mapData['field'], $mapData['attribute']), Zend_Log::WARN);
334
- unset($configMap[$k]);
335
- continue;
336
- }
337
- $attribute->setStoreId($this->getData('store_id'));
338
- $this->_aAttributes[$attribute->getAttributeCode()] = $attribute;
339
- }
340
- }
341
-
342
- foreach ($configMap as $mapData)
343
- {
344
- $this->_aFieldMap[$mapData['field']] = $mapData;
345
- }
346
- }
347
-
348
- return $this->_aFieldMap;
349
- }
350
-
351
- /**
352
- * Adds a product to the XML feed by rewriting the attribute names
353
- * @param unknown_type $aData
354
- * @param unknown_type $oFeedProduct
355
- */
356
- private function _addProductToXml(Sooqr_Feed_Model_Map_Product_Abstract $oProductMap)
357
- {
358
- try
359
- {
360
- $aProducts = $oProductMap->map();
361
- if ($oProductMap->isSkip())
362
- {
363
- $this->_count_products_skipped++;
364
- return $this;
365
- }
366
-
367
- // Add subproducts for a configurable product
368
- if ($oProductMap->getProduct()->getTypeId() == Mage_Catalog_Model_Product_Type::TYPE_CONFIGURABLE
369
- && $oProductMap->hasAssocMaps()
370
- && $oProductMap->getIsVariants())
371
- {
372
- foreach ($oProductMap->getAssocMaps() as $assocMap)
373
- {
374
- if ($assocMap->isSkip())
375
- {
376
- $this->_count_products_skipped++;
377
- }
378
- }
379
- }
380
-
381
- // Merge subproducts with parent product
382
- if (($iProducts = count($aProducts)) > 1)
383
- {
384
- $aProducts[0] = array_filter($aProducts[0]);
385
- $aProducts[0]['sqr:assoc_id'] = $aProducts[0]['id'];
386
-
387
- for ($iProduct = 1; $iProduct < $iProducts; $iProduct++)
388
- {
389
- $aProducts[$iProduct] = array_merge($aProducts[0], array_filter($aProducts[$iProduct]));
390
- $aProducts[$iProduct]['sqr:assoc_id'] = $aProducts[0]['id'];
391
- }
392
- }
393
-
394
- foreach ($aProducts as $aProduct)
395
- {
396
- $this->_oXmlWriter->startElement($this->sProductElement);
397
-
398
- foreach ($aProduct as $field => $value)
399
- {
400
- // Skip empty fields
401
- if (is_array($value))
402
- {
403
- if (count($value) == 0)
404
- {
405
- continue;
406
- }
407
- }
408
- else
409
- {
410
- $value = trim($value);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
411
  if (strlen($value) == 0)
412
  {
413
  continue;
414
  }
415
- }
416
-
417
- // Remove the namespace from the fieldname
418
- if (strpos($field, ':') !== false)
419
- {
420
- list($sNamespace, $field) = explode(':', $field);
421
- }
422
- // Check if this field should have an namespace
423
- else if (array_key_exists($field, $this->_aFieldNamespaces))
424
- {
425
- $sNamespace = $this->_aFieldNamespaces[$field];
426
- }
427
- else
428
- {
429
- $sNamespace = null;
430
- }
431
-
432
- $this->_oXmlWriter->startElementNs($sNamespace, $field, null);
433
-
434
- if (!is_array($value))
435
- {
436
- $value = array($value);
437
- }
438
- $isMultiValued = count($value) > 1;
439
-
440
- foreach ($value as $_val)
441
- {
442
- // Multiple values are added to seperate nodes
443
- if ($isMultiValued)
444
- {
445
- $this->_oXmlWriter->startElement('node');
446
- }
447
-
448
- // Some nodes should be added as CDATA
449
- if (in_array($field, $this->aCDataNodes)
450
- || strpos($_val, '&') !== false)
451
- {
452
- $this->_oXmlWriter->writeCData($_val);
453
- }
454
- else
455
- {
456
- $this->_oXmlWriter->text($_val);
457
- }
458
-
459
  if ($isMultiValued)
460
  {
461
  $this->_oXmlWriter->endElement();
462
  }
463
- }
464
-
465
  $this->_oXmlWriter->endElement();
466
- }
467
-
468
- $this->_oXmlWriter->endElement();
469
- }
470
- }
471
- catch (Exception $e)
472
- {
473
- $this->log($e->getMessage(), Zend_Log::ERR);
474
- }
475
- }
476
-
477
- private function getSanitized($aData)
478
- {
479
- $aSanitized = array();
480
- foreach ($aData as $k => $val)
481
- {
482
- $aSanitized[$k] = str_replace($this->aBadChars, $this->aReplaceChars, $val);
483
- }
484
-
485
- return $aSanitized;
486
- }
487
-
488
- public function getCategories($oProduct)
489
- {
490
- $aIds = $oProduct->getCategoryIds();
491
- $aCategories = array();
492
- foreach ($aIds as $iCategory)
493
- {
494
- $oCategory = Mage::getModel('catalog/category')->load($iCategory);
495
- $aCategories[$oCategory->getLevel()-1] = $oCategory->getName();
496
- }
497
-
498
- return $aCategories;
499
- }
500
-
501
- /**
502
- * Outputs the correct content type header
503
- *
504
- */
505
- private function _sendHeader()
506
- {
507
- header('Content-type: text/xml; charset="utf-8"', true);
508
- }
509
-
510
- static private function _debug($m)
511
- {
512
- echo '<pre>';
513
- var_dump($m);
514
- echo '</pre>';
515
- }
516
-
517
- protected function _getProductCollection(Mage_Core_Model_Store $oStore, $offset = 0, $limit = 0)
518
- {
519
- $collection = Mage::getModel('catalog/product')
520
- ->setStoreId($oStore->getStoreId())
521
- ->getCollection();
522
-
523
- // Products should be enabled
524
- $collection->addAttributeToFilter('status', 1);
525
-
526
- // Disable specific product types
527
- $this->_addProductTypeToFilter($collection);
528
-
529
- // Products should have visibility for the search
530
- $visibility = array(
531
- Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH,
532
- Mage_Catalog_Model_Product_Visibility::VISIBILITY_IN_SEARCH
533
- );
534
-
535
- $collection->addAttributeToFilter('visibility', $visibility);
536
- $collection->addAttributeToSelect('*');
537
-
538
- // Limit the number of products in this collection
539
- if ($limit != 0)
540
- {
541
- $collection->getSelect()->limit($limit, $offset);
542
- }
543
-
544
- return $collection;
545
- }
546
-
547
- /**
548
- * Returns the file path where the cached version of the product feed will be stored
549
- * @param $temporary boolean true if we want a temporary path
550
- * @return string
551
- */
552
- protected function _getFeedPath($temporary = false)
553
- {
554
- $path = rtrim(Mage::getConfig()->getTempVarDir(), DS).DS.'sooqr-feed'.
555
- DS.sprintf('feed-%s.%s', $this->_sCurrentStoreCode, $temporary ? 'xml.tmp' : 'xml');
556
-
557
- // Generate the parent path recursively
558
- if (!file_exists(dirname($path)))
559
- {
560
- mkdir(dirname($path), 0777, true);
561
- }
562
-
563
- return $path;
564
- }
565
-
566
- /**
567
- * Check for a valid cached feed XML
568
- *
569
- * @return boolean true if a cache file exists, otherwise false
570
- */
571
- protected function _checkFeedPath()
572
- {
573
- $feedPath = $this->_getFeedPath();
574
-
575
- // Check if the file exists, is readable and contains data
576
- return file_exists($feedPath) && is_readable($feedPath) && filesize($feedPath) > 0;
577
- }
578
-
579
- protected function _streamCacheFileToBrowser($exitAfterStream = true)
580
- {
581
- $this->_sendHeader();
582
-
583
- $feedPath = $this->_getFeedPath();
584
-
585
- readfile($feedPath);
586
-
587
- if ($exitAfterStream)
588
- {
589
- exit;
590
- }
591
- }
592
-
593
- /**
594
- * @param int $type_id
595
- * @param array $args
596
- * @return Sooqr_Feed_Model_Map_Product_Abstract
597
- */
598
- protected function _getProductMapModel($typeId, $args = array())
599
- {
600
- $params = array(
601
- 'store_code' => $this->_sCurrentStoreCode,
602
- 'store_id' => $this->_iCurrentStoreId,
603
- 'website_id' => $this->_iCurrentWebsiteId,
604
- );
605
-
606
- $isAssoc = isset($args['is_assoc']) && $args['is_assoc'] ? true : false;
607
-
608
- switch ($typeId)
609
- {
610
- case 'simple':
611
- if ($isAssoc)
612
- {
613
- $oProductMap = Mage::getModel('feed/map_product_associated', $params);
614
- }
615
- else
616
- {
617
- $oProductMap = Mage::getModel('feed/map_product_simple', $params);
618
- }
619
- break;
620
-
621
- case 'abstract':
622
- case 'configurable':
623
- case 'bundle':
624
- case 'downloadable':
625
- case 'grouped':
626
- case 'virtual':
627
- $oProductMap = Mage::getModel('feed/map_product_'.$typeId, $params);
628
- break;
629
-
630
- default:
631
- return null;
632
- }
633
-
634
- return $oProductMap;
635
- }
636
-
637
- /**
638
- * Returns the cached attribute object for the specifies attribute code
639
- * @param unknown_type $code
640
- * @return boolean
641
- */
642
- public function getAttribute($code)
643
- {
644
- if (isset($this->_aAttributes[$code]))
645
- {
646
- return $this->_aAttributes[$code];
647
- }
648
-
649
- return false;
650
- }
651
-
652
- public function getTools()
653
- {
654
- return Mage::getSingleton('feed/tools');
655
- }
656
-
657
- /**
658
- * General logging method
659
- *
660
- * @param string $msg
661
- * @param integer $level
662
- */
663
- public function log($msg, $level = null)
664
- {
665
- if (is_null($level))
666
- {
667
- $level = Zend_Log::INFO;
668
- }
669
-
670
- $m = memory_get_usage();
671
- $units = array('b', 'Kb', 'Mb', 'Gb', 'Tb', 'Pb');
672
- $mem = @round($m / pow(1024, ($i = floor(log($m, 1024)))), 2).' '.$units[$i];
673
- $msg = sprintf('(mem %4.2f %s) ', $mem, $units[$i]).$msg;
674
-
675
- Mage::log($msg, $level, $this->getData('log_filename'), $this->getData('force_log'));
676
- }
677
-
678
- protected function _addProductTypeToFilter($collection)
679
- {
680
- $allProductTypes = array(
681
- Mage_Catalog_Model_Product_Type::TYPE_BUNDLE,
682
- Mage_Catalog_Model_Product_Type::TYPE_CONFIGURABLE,
683
- Mage_Downloadable_Model_Product_Type::TYPE_DOWNLOADABLE,
684
- Mage_Catalog_Model_Product_Type::TYPE_GROUPED,
685
- Mage_Catalog_Model_Product_Type::TYPE_SIMPLE,
686
- Mage_Catalog_Model_Product_Type::TYPE_VIRTUAL,
687
- );
688
- $configedTypes = $this->getConfigVar('product_types');
689
- $configedTypes = explode(',', $configedTypes);
690
- $disabledTypes = array_diff($allProductTypes, $configedTypes);
691
-
692
- // Check if we should disable specific types
693
- if (count($disabledTypes) > 0)
694
- {
695
- $collection->addAttributeToFilter('type_id', array('nin' => $disabledTypes));
696
- }
697
-
698
- return $collection;
699
- }
700
-
701
- protected function _stopOnException(Exception $e)
702
- {
703
- if ($this->getCliMode())
704
- {
705
- printf('Fatal error during script execution: ');
706
- echo $e->getMessage()."\n";
707
- }
708
- else
709
- {
710
- header('HTTP/1.1 500 Internal Server Error', true, 500);
711
- echo $e->getMessage()."\n";
712
- }
713
-
714
- die;
715
- }
716
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
717
  }
1
+ <?php
2
+
3
+ class Sooqr_Feed_Model_Generator extends Varien_Object
4
+ {
5
+ const THUMBNAIL_WIDTH = 120;
6
+ const THUMBNAIL_HEIGHT = 120;
7
+
8
+ const LOGFILE = 'sooqr.log';
9
+
10
+ const GETCATEGORIES_ACTIVEONLY = 1;
11
+
12
+ private $sProductElement = 'item';
13
+ private $oProductModel;
14
+ private $aBadChars = array('"',"\r\n","\n","\r","\t");
15
+ private $aReplaceChars = array(""," "," "," ","");
16
+
17
+ private $oTagModel = null;
18
+
19
+ private $_oXmlWriter;
20
+ private $_oProducts;
21
+ private $_iProductCount;
22
+ private $_iBatchSize;
23
+ private $_oCurrentStore;
24
+ private $_iCurrentStoreId;
25
+ private $_iCurrentWebsiteId;
26
+ private $_sCurrentStoreCode;
27
+ private $_sCurrentStoreSuffix;
28
+ private $_oCollection;
29
+ private $_aFieldMap = null;
30
+ private $_aAttributes = null;
31
+ private $_tools = null;
32
+
33
+ private $aCDataNodes = array(
34
+ 'description', 'link', 'image_link',
35
+ );
36
+
37
+ private $_aCategoryCache = array();
38
+
39
+ private $_aNamespaces = array(
40
+ 'g' => 'http://base.google.com/ns/1.0',
41
+ 'sqr' => 'http://base.sooqr.com/ns/1.0',
42
+ );
43
+
44
+ private $_aFieldNamespaces = array(
45
+ 'id' => 'g',
46
+ 'price' => 'g',
47
+ 'normal_price' => 'sqr',
48
+ 'mpn' => 'g',
49
+ 'brand' => 'g',
50
+ 'currency' => 'sqr',
51
+ 'magento_store' => 'sqr',
52
+ 'attribute_set' => 'sqr',
53
+ 'category0' => 'sqr',
54
+ 'category1' => 'sqr',
55
+ 'category2' => 'sqr',
56
+ 'category3' => 'sqr',
57
+ 'category4' => 'sqr',
58
+ 'category5' => 'sqr',
59
+ 'category6' => 'sqr',
60
+ 'category7' => 'sqr',
61
+ 'category8' => 'sqr',
62
+ 'category9' => 'sqr',
63
+ 'tag_words' => 'sqr',
64
+ 'product_object_type' => 'sqr',
65
+ 'all_sku' => 'sqr',
66
+ 'stock' => 'sqr',
67
+ 'in_stock' => 'sqr',
68
+ 'stock_status' => 'sqr',
69
+ );
70
+
71
+ /**
72
+ * Set a boolean so the cronjob knows when to recreate the images
73
+ * @param bool $recreate - boolean true recreate images
74
+ */
75
+ public function setRecreateImages($recreate = true)
76
+ {
77
+ Mage::getConfig()->saveConfig('sooqr/images/recreate', $recreate );
78
+ // When the script is called again the same config is used if this script is not finished yet, so reload the config
79
+ Mage::getConfig()->reinit();
80
+ Mage::app()->reinitStores();
81
+ }
82
+
83
+ /**
84
+ * This function is called by the Magento cronjob.
85
+ * It checks if the images has to be recreated.
86
+ */
87
+ public function checkRecreateImages()
88
+ {
89
+ if(Mage::getStoreConfig('sooqr/images/recreate'))
90
+ {
91
+ Mage::log('Staring to recreated images', null, self::LOGFILE);
92
+ // Stop the next cronjob from recreate the images also
93
+ $this->setRecreateImages(false);
94
+ // Recreate the Sooqr feed images
95
+ $this->resizeImages();
96
+ }
97
+ }
98
+
99
+ /**
100
+ * Recreate the Sooqr feed images from every store
101
+ */
102
+ public function resizeImages()
103
+ {
104
+ Mage::log('Caching of images started', null, self::LOGFILE);
105
+
106
+ // Loop the stores
107
+ $allStores = Mage::app()->getStores();
108
+ foreach ($allStores as $_eachStoreId => $val)
109
+ {
110
+ $_store = Mage::app()->getStore($_eachStoreId);
111
+ $_storeId = $_store->getId();
112
+ if(Mage::getStoreConfig('sooqr/feed/enabled', $_storeId) !== 0)
113
+ {
114
+ Mage::app()->setCurrentStore($_storeId);
115
+ $collection = $this->_getProductCollection($_store);
116
+
117
+ // Loop all the products
118
+ foreach ($collection as $product) {
119
+ $image = $product->getData('image');
120
+ if ($image != 'no_selection' && $image != "")
121
+ {
122
+ // Create a thumnail image
123
+ $fieldData = (string)Mage::helper('catalog/image')->init($product, 'small_image')->resize(self::THUMBNAIL_WIDTH);
124
+ }
125
+ }
126
+ }
127
+ }
128
+
129
+ Mage::log('Caching of images completed', null, self::LOGFILE);
130
+ }
131
+
132
+ public function runFromEvent()
133
+ {
134
+ $this->setData('cli_mode', true);
135
+ $this->setData('store_code', Mage_Core_Model_Store::DEFAULT_CODE);
136
+ $this->run();
137
+ }
138
+
139
+ public function run()
140
+ {
141
+ // Enabled browser debugging
142
+ if ($this->getConfigVar('debugging', null, 'advanced') == 1
143
+ || $this->getDebug() == true)
144
+ {
145
+ error_reporting(E_ALL);
146
+ ini_set('display_errors', 'On');
147
+ }
148
+
149
+ if ($this->getConfigVar('enabled') == 1)
150
+ {
151
+ Mage::log('Feed generation started', null, self::LOGFILE);
152
+
153
+ // Required for enabling catalog price rules
154
+ Mage::app()->loadAreaPart(Mage_Core_Model_App_Area::AREA_FRONTEND,Mage_Core_Model_App_Area::PART_EVENTS);
155
+
156
+ $this->_iBatchSize = $this->getConfigVar('batch_size');
157
+
158
+ // Initialize the current store settings
159
+ if (!$this->hasData('store_code'))
160
+ {
161
+ $this->setData('store_code', Mage_Core_Model_Store::DEFAULT_CODE);
162
+ }
163
+
164
+ // Try to load the specified store code
165
+ try
166
+ {
167
+ $this->_oCurrentStore = Mage::app()->getStore($this->getData('store_code'));
168
+ }
169
+ catch (Exception $e)
170
+ {
171
+ $e->setMessage(sprintf('Store with code \'%s\' doesn\'t exists.', $this->getData('store_code')));
172
+ $this->_stopOnException($e);
173
+ }
174
+
175
+ $this->_iCurrentStoreId = $this->getData('store_id');
176
+ $this->_iCurrentStoreId = $this->_oCurrentStore->getStoreId();
177
+ $this->_sCurrentStoreCode = $this->_oCurrentStore->getCode();
178
+ $this->_iCurrentWebsiteId = $this->_oCurrentStore->getWebsiteId();
179
+
180
+ // For multiple store views, use prefixes for the product ID's
181
+ if ($this->_sCurrentStoreCode == 'default')
182
+ {
183
+ $this->_sCurrentStoreSuffix = '';
184
+ }
185
+ else
186
+ {
187
+ $this->_sCurrentStoreSuffix = '_'.$this->_oCurrentStore->getCode();
188
+ }
189
+
190
+ // Check if we are running the export from the command line script
191
+ if ($this->getCliMode())
192
+ {
193
+ // Check if we should process in background
194
+ if ($this->getConfigVar('background_mode') == 1)
195
+ {
196
+ $this->_generateFeed();
197
+
198
+ Mage::log('Feed generation completed', null, self::LOGFILE);
199
+ }
200
+ else
201
+ {
202
+ throw new Exception('This script should only be run when background_mode is enabled in the Sooqr Feed configuration.');
203
+ }
204
+ }
205
+ else
206
+ {
207
+ // Check if we should generate the feed on the fly
208
+ if (($this->getConfigVar('background_mode') == 0
209
+ || $this->getReload()))
210
+ {
211
+ $this->_generateFeed();
212
+ }
213
+
214
+ if (!$this->_checkFeedPath())
215
+ {
216
+ header('HTTP/1.1 404 Feed does not exist', true, 404);
217
+ echo 'The requested datafeed is currently not available.';
218
+ exit;
219
+ }
220
+ else
221
+ {
222
+ Mage::log('Feed generation completed', null, self::LOGFILE);
223
+
224
+ // Output the generated feed to the browser
225
+ $this->_streamCacheFileToBrowser();
226
+ }
227
+ }
228
+ }
229
+ }
230
+
231
+ /**
232
+ * @return RocketWeb_GoogleBaseFeedGenerator_Model_Generator
233
+ */
234
+ protected function _loadAdditionalAttributes()
235
+ {
236
+ $codes = array('status');
237
+ $product = Mage::getModel('catalog/product')->setStoreId($this->getData('store_id'));
238
+ foreach ($codes as $attribute_code) {
239
+ $attribute = $product->getResource()->getAttribute($attribute_code);
240
+ $this->_aAttributes[$attribute->getAttributeCode()] = $attribute;
241
+ }
242
+
243
+ return $this;
244
+ }
245
+
246
+ private function _generateFeed()
247
+ {
248
+ if (ob_get_status())
249
+ {
250
+ ob_end_clean();
251
+ }
252
+ $this->_loadAdditionalAttributes();
253
+
254
+ $this->_initFeed();
255
+
256
+ // Set store so run from the command line it uses the correct store
257
+ Mage::app()->setCurrentStore($this->_iCurrentStoreId);
258
+
259
+ // Initialize tools object
260
+ $this->_tools = $this->getTools();
261
+
262
+ // Load the tag model for processing product tags
263
+ $this->oTagModel = Mage::getModel('tag/tag');
264
+
265
+ $this->_initProducts($this->_oCurrentStore);
266
+ $page = isset($_GET['page']) && $_GET['page'] > 0 ? intval($_GET['page']) : false;
267
+ $exportLimit = !is_null($this->getLimit()) ? $this->getLimit() : $this->_iProductCount;
268
+ $exportLimit = $page !== false ? min($exportLimit, ($page * $this->_iBatchSize)) : $exportLimit;
269
+ $start = $page === false ? 0 : min($exportLimit, (($page - 1) * $this->_iBatchSize));
270
+ for ($iProductOffset = $start; $iProductOffset < $exportLimit; $iProductOffset += $this->_iBatchSize)
271
+ {
272
+ $batchSize = min($exportLimit - $iProductOffset, $this->_iBatchSize);
273
+ $collection = $this->_getProductCollection($this->_oCurrentStore, $iProductOffset,
274
+ $batchSize);
275
+
276
+ Mage::getSingleton('core/resource_iterator')->walk($collection->getSelect(),
277
+ array(array($this, 'addProductToFeed')));
278
+
279
+ // Flushes all processed products to disk
280
+ $this->_flushFeed();
281
+ }
282
+
283
+ $this->_closeFeed();
284
+ }
285
+
286
+ public function getConfig()
287
+ {
288
+ return Mage::getSingleton('feed/config');
289
+ }
290
+
291
+ public function getConfigVar($key, $storeId = null, $section = 'feed')
292
+ {
293
+ return $this->getConfig()->getConfigVar($key, $storeId, $section);
294
+ }
295
+
296
+ /**
297
+ * Initialises the basic feed object and flushes this information to disk
298
+ *
299
+ */
300
+ private function _initFeed()
301
+ {
302
+ $this->_oXmlWriter = new XMLWriter();
303
+ $this->_oXmlWriter->openMemory();
304
+ $this->_oXmlWriter->startDocument('1.0', 'UTF-8');
305
+
306
+ // Output the parent rss tag
307
+ $this->_oXmlWriter->startElement('rss');
308
+ $this->_oXmlWriter->writeAttribute('version', '2.0');
309
+
310
+ foreach ($this->_aNamespaces as $prefix => $uri)
311
+ {
312
+ $this->_oXmlWriter->writeAttributeNs('xmlns', $prefix, null, $uri);
313
+ }
314
+
315
+ $this->_oXmlWriter->startElement('channel');
316
+ $this->_oXmlWriter->writeElement('title', 'Product feed');
317
+ $this->_oXmlWriter->startElement('link');
318
+ $this->_oXmlWriter->writeCData(Mage::getBaseUrl().ltrim($_SERVER['REQUEST_URI'], '/'));
319
+ $this->_oXmlWriter->endElement();
320
+ $this->_oXmlWriter->writeElement('pubDate', strftime('%a, %d %b %Y %H:%M:%S %Z'));
321
+ $this->_oXmlWriter->writeElement('generator', 'MagentoSooqr/'.Mage::getConfig()->getModuleConfig("Sooqr_Feed")->version);
322
+ $this->_oXmlWriter->writeElement('description', 'Magento Product feed for Sooqr');
323
+
324
+ // Flush the current contents to disk
325
+ if (file_put_contents($this->_getFeedPath(true), $this->_oXmlWriter->flush()) === false)
326
+ {
327
+ throw new Exception(sprintf('Cannot write to temporary feed file: %s', $this->_getFeedPath(true)));
328
+ }
329
+ }
330
+
331
+ /**
332
+ * Flushes all the products from memory to disk
333
+ */
334
+ private function _flushFeed()
335
+ {
336
+ file_put_contents($this->_getFeedPath(true), $this->_oXmlWriter->flush(true), FILE_APPEND);
337
+ }
338
+
339
+ /**
340
+ * Close the feed tags and write the last parts to disk
341
+ *
342
+ */
343
+ private function _closeFeed()
344
+ {
345
+ $this->_oXmlWriter->endElement(); // Channel
346
+ $this->_oXmlWriter->endElement(); // RSS
347
+ $this->_oXmlWriter->endDocument();
348
+
349
+ $this->_flushFeed();
350
+
351
+ // Move the completed feed to the actual cached version
352
+ if (!rename($this->_getFeedPath(true), $this->_getFeedPath()))
353
+ {
354
+ throw new Exception(sprintf('Cannot (over)write feed file cache: %s', $this->_getFeedPath()));
355
+ }
356
+ }
357
+
358
+ /**
359
+ * Retrieves a set of products from the Magento system.
360
+ *
361
+ * @param Mage_Core_Model_Store $oStore reference to the active store object
362
+ */
363
+ private function _initProducts(Mage_Core_Model_Store $oStore)
364
+ {
365
+ $collection = $this->_getProductCollection($oStore);
366
+ $this->_iProductCount = $collection->getSize();;
367
+ }
368
+
369
+ /**
370
+ * Adds a product to the XML feed
371
+ *
372
+ * @param integer $iProduct
373
+ */
374
+ public function addProductToFeed($args)
375
+ {
376
+ $row = $args['row'];
377
+ $parentEntityId = null;
378
+
379
+ // Initialize the mapping for this product type
380
+ if (is_null($oProductMap = $this->_getProductMapModel($row['type_id'], array())))
381
+ {
382
+ return false;
383
+ }
384
+
385
+ // Load the current product
386
+ $oProduct = Mage::getModel('catalog/product');
387
+ $oProduct->setData($row);
388
+ $oProduct->setStoreId($this->_iCurrentStoreId);
389
+ $oProduct->getResource()->load($oProduct, $row['entity_id']);
390
+
391
+ // Initialize the product map for this product type
392
+ $oProductMap->setGenerator($this)
393
+ ->setProduct($oProduct)
394
+ ->setFieldsMap($this->_getFieldsMap())
395
+ ->initialize();
396
+
397
+ // Check if the product should be skipped
398
+ if ($oProductMap->checkSkipSubmission()->isSkip())
399
+ {
400
+ return;
401
+ }
402
+
403
+ // Add the product to the XML output
404
+ $this->_addProductToXml($oProductMap);
405
+
406
+ // Clear the product map data
407
+ $oProductMap->unsetData();
408
+ }
409
+
410
+ protected function _getFieldsMap()
411
+ {
412
+ // Check if we have cached this information
413
+ if (!is_null($this->_aFieldMap))
414
+ {
415
+ return $this->_aFieldMap;
416
+ }
417
+
418
+ $this->_aFieldMap = array();
419
+
420
+ $product = Mage::getModel('catalog/product')->setStoreId($this->getData('store_id'));
421
+
422
+ $variables = array('field_map');
423
+ if ($this->getConfigVar('export_all_user_attributes') != 1)
424
+ {
425
+ $variables[] = 'custom_field_map';
426
+ }
427
+
428
+ foreach ($variables as $variable)
429
+ {
430
+ // Load attributes used. Exclude columns with attributes that doesn't exist.
431
+ $tmpMap = $configMap = $this->getConfigVar($variable);
432
+ foreach ($tmpMap as $k => $mapData)
433
+ {
434
+ // Check if the supplied variable is a directive
435
+ if (!$this->getConfig()->isDirective($mapData['attribute'], $this->getData('store_id')))
436
+ {
437
+ // Check if the attribute exists
438
+ $attribute = $product->getResource()->getAttribute($mapData['attribute']);
439
+ if ($attribute === false)
440
+ {
441
+ $this->log(sprintf("Field '%s' ignored, can't find attribute with code '%s'.", $mapData['field'], $mapData['attribute']), Zend_Log::WARN);
442
+ unset($configMap[$k]);
443
+ continue;
444
+ }
445
+ $attribute->setStoreId($this->getData('store_id'));
446
+ $this->_aAttributes[$attribute->getAttributeCode()] = $attribute;
447
+ }
448
+ }
449
+
450
+ foreach ($configMap as $mapData)
451
+ {
452
+ $this->_aFieldMap[$mapData['field']] = $mapData;
453
+ }
454
+ }
455
+
456
+ return $this->_aFieldMap;
457
+ }
458
+
459
+ /**
460
+ * Adds a product to the XML feed by rewriting the attribute names
461
+ * @param unknown_type $aData
462
+ * @param unknown_type $oFeedProduct
463
+ */
464
+ private function _addProductToXml(Sooqr_Feed_Model_Map_Product_Abstract $oProductMap)
465
+ {
466
+ try
467
+ {
468
+ $aProducts = $oProductMap->map();
469
+ if ($oProductMap->isSkip())
470
+ {
471
+ $this->_count_products_skipped++;
472
+ return $this;
473
+ }
474
+ // Add subproducts for a configurable product
475
+ if ($oProductMap->getProduct()->getTypeId() == Mage_Catalog_Model_Product_Type::TYPE_CONFIGURABLE
476
+ && $oProductMap->hasAssocMaps()
477
+ && $oProductMap->getIsVariants())
478
+ {
479
+ foreach ($oProductMap->getAssocMaps() as $assocMap)
480
+ {
481
+ if ($assocMap->isSkip())
482
+ {
483
+ $this->_count_products_skipped++;
484
+ }
485
+ }
486
+ }
487
+ // Merge subproducts with parent product
488
+ if (($iProducts = count($aProducts)) > 1)
489
+ {
490
+ $aProducts[0] = array_filter($aProducts[0]);
491
+ $aProducts[0]['sqr:assoc_id'] = $aProducts[0]['id'];
492
+ for ($iProduct = 1; $iProduct < $iProducts; $iProduct++)
493
+ {
494
+ $aProducts[$iProduct] = array_merge($aProducts[0], array_filter($aProducts[$iProduct]));
495
+ $aProducts[$iProduct]['sqr:assoc_id'] = $aProducts[0]['id'];
496
+ }
497
+ }
498
+
499
+ foreach ($aProducts as $aProduct)
500
+ {
501
+ $this->_oXmlWriter->startElement($this->sProductElement);
502
+ $this->_oXmlWriter->startElement('content_type');
503
+ $this->_oXmlWriter->text("product");
504
+ $this->_oXmlWriter->endElement();
505
+ foreach ($aProduct as $field => $value)
506
+ {
507
+ // Skip empty fields
508
+ if (is_array($value))
509
+ {
510
+ if (count($value) == 0)
511
+ {
512
+ continue;
513
+ }
514
+ else if ($field == 'tag_words')
515
+ {
516
+ $value = join(', ', $value);
517
+ }
518
+ }
519
+ else
520
+ {
521
+ $value = trim($value);
522
  if (strlen($value) == 0)
523
  {
524
  continue;
525
  }
526
+ }
527
+
528
+ // Remove the namespace from the fieldname
529
+ if (strpos($field, ':') !== false)
530
+ {
531
+ list($sNamespace, $field) = explode(':', $field);
532
+ }
533
+ // Check if this field should have an namespace
534
+ else if (array_key_exists($field, $this->_aFieldNamespaces))
535
+ {
536
+ $sNamespace = $this->_aFieldNamespaces[$field];
537
+ }
538
+ else
539
+ {
540
+ $sNamespace = null;
541
+ }
542
+
543
+ $this->_oXmlWriter->startElementNs($sNamespace, $field, null);
544
+
545
+ if (!is_array($value))
546
+ {
547
+ $value = array($value);
548
+ }
549
+ // $value = $this->getSanitized($value);
550
+ $isMultiValued = count($value) > 1;
551
+
552
+ foreach ($value as $_val)
553
+ {
554
+ // Multiple values are added to seperate nodes
555
+ if ($isMultiValued)
556
+ {
557
+ $this->_oXmlWriter->startElement('node');
558
+ }
559
+
560
+ $_val = str_replace(array("\t", "\x0B"), ' ', $_val);
561
+
562
+ $this->addXmlNode($field, $_val);
563
+
 
 
 
 
 
 
564
  if ($isMultiValued)
565
  {
566
  $this->_oXmlWriter->endElement();
567
  }
568
+ }
569
+
570
  $this->_oXmlWriter->endElement();
571
+ }
572
+
573
+ $this->_oXmlWriter->endElement();
574
+ }
575
+ }
576
+ catch (Exception $e)
577
+ {
578
+ $this->log($e->getMessage(), Zend_Log::ERR);
579
+ }
580
+ }
581
+
582
+ function addXmlNode($field, $_val)
583
+ {
584
+ if(is_array($_val))
585
+ {
586
+ foreach($_val as $v)
587
+ {
588
+ $this->addXmlNode($field, $v);
589
+ }
590
+ return ;
591
+ }
592
+ // Some nodes should be added as CDATA
593
+ if (in_array($field, $this->aCDataNodes)
594
+ || strpos($_val, '&') !== false)
595
+ {
596
+ $this->_oXmlWriter->writeCData($_val);
597
+ }
598
+ else
599
+ {
600
+ $this->_oXmlWriter->text($_val);
601
+ }
602
+ }
603
+
604
+ private function getSanitized($aData)
605
+ {
606
+ $aSanitized = array();
607
+ foreach ($aData as $k => $val)
608
+ {
609
+ $aSanitized[$k] = $this->_tools->convertEntities($val);
610
+ }
611
+
612
+ return $aSanitized;
613
+ }
614
+
615
+ public function getCategories($oProduct, $iFlags = 0)
616
+ {
617
+ $aIds = $oProduct->getAvailableInCategories();
618
+
619
+ $aCategoryIds = array();
620
+
621
+ // Fetch all parent categoryIDs for each assigned category
622
+ foreach ($aIds as $iCategory)
623
+ {
624
+ // Load the category into the cache
625
+ $this->_aCategoryCache[$iCategory] = Mage::getModel('catalog/category')->load($iCategory);
626
+ $oCategory = $this->_aCategoryCache[$iCategory];
627
+
628
+ $aCategoryWithParentIds = array_merge($oCategory->getParentIds(), array($iCategory));
629
+
630
+ foreach ($aCategoryWithParentIds as $iCategoryId)
631
+ {
632
+ if (!isset($this->_aCategoryCache[$iCategoryId]))
633
+ {
634
+ $this->_aCategoryCache[$iCategoryId] = Mage::getModel('catalog/category')->load($iCategoryId);
635
+ }
636
+ if (($iFlags & self::GETCATEGORIES_ACTIVEONLY) > 0
637
+ && $this->_aCategoryCache[$iCategoryId]->getIsActive() === "0")
638
+ {
639
+ continue 2;
640
+ }
641
+ }
642
+
643
+ $aCategoryIds = array_merge($aCategoryIds, $aCategoryWithParentIds);
644
+ }
645
+
646
+ $aCategoryIds = array_unique($aCategoryIds);
647
+ $aCategories = array();
648
+
649
+ // Link the category properties to the product
650
+ foreach ($aCategoryIds as $iCategory)
651
+ {
652
+ $oCategory = $this->_aCategoryCache[$iCategory];
653
+
654
+ if ($oCategory->getLevel() >= 2)
655
+ {
656
+ if (isset($aCategories[$oCategory->getLevel()-1]))
657
+ {
658
+ if (!is_array($aCategories[$oCategory->getLevel()-1]))
659
+ {
660
+ $aCategories[$oCategory->getLevel()-1] = array($aCategories[$oCategory->getLevel()-1]);
661
+ }
662
+ if (!in_array($oCategory->getName(), $aCategories[$oCategory->getLevel()-1]))
663
+ {
664
+ $aCategories[$oCategory->getLevel()-1][] = $oCategory->getName();
665
+ }
666
+ }
667
+ else
668
+ {
669
+ $aCategories[$oCategory->getLevel()-1] = $oCategory->getName();
670
+ }
671
+ }
672
+ }
673
+
674
+ // Sort by category level
675
+ if (count($aCategories))
676
+ {
677
+ ksort($aCategories);
678
+ }
679
+
680
+ return $aCategories;
681
+ }
682
+
683
+ /**
684
+ * Outputs the correct content type header
685
+ *
686
+ */
687
+ private function _sendHeader()
688
+ {
689
+ header('Content-type: text/xml; charset="utf-8"', true);
690
+ }
691
+
692
+ static private function _debug($m)
693
+ {
694
+ echo '<pre>';
695
+ var_dump($m);
696
+ echo '</pre>';
697
+ }
698
+
699
+ protected function _getProductCollection(Mage_Core_Model_Store $oStore, $offset = 0, $limit = 0)
700
+ {
701
+ $collection = Mage::getModel('catalog/product')
702
+ //->setStoreId($oStore->getStoreId())
703
+ ->getCollection();
704
+
705
+ // Filter on current store
706
+ $collection->addStoreFilter($oStore->getStoreId());
707
+
708
+ // Products should be enabled
709
+ $collection->addAttributeToFilter('status', 1);
710
+
711
+ // Disable specific product types
712
+ $this->_addProductTypeToFilter($collection);
713
+
714
+ // Products should have visibility for the search
715
+ $visibility = array(
716
+ Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH,
717
+ Mage_Catalog_Model_Product_Visibility::VISIBILITY_IN_SEARCH
718
+ );
719
+
720
+ $collection->addAttributeToFilter('visibility', $visibility);
721
+ $collection->addAttributeToSelect('*');
722
+
723
+ // Limit the number of products in this collection
724
+ if ($limit != 0)
725
+ {
726
+ $collection->getSelect()->limit($limit, $offset);
727
+ }
728
+
729
+ return $collection;
730
+ }
731
+
732
+ /**
733
+ * Returns the file path where the cached version of the product feed will be stored
734
+ * @param $temporary boolean true if we want a temporary path
735
+ * @return string
736
+ */
737
+ protected function _getFeedPath($temporary = false)
738
+ {
739
+ $path = rtrim(Mage::getConfig()->getTempVarDir(), DS).DS.'sooqr-feed'.
740
+ DS.sprintf('feed-%s.%s', $this->_sCurrentStoreCode, $temporary ? 'xml.tmp' : 'xml');
741
+
742
+ // Generate the parent path recursively
743
+ if (!file_exists(dirname($path)))
744
+ {
745
+ mkdir(dirname($path), 0777, true);
746
+ }
747
+
748
+ return $path;
749
+ }
750
+
751
+ /**
752
+ * Check for a valid cached feed XML
753
+ *
754
+ * @return boolean true if a cache file exists, otherwise false
755
+ */
756
+ protected function _checkFeedPath()
757
+ {
758
+ $feedPath = $this->_getFeedPath();
759
+
760
+ // Check if the file exists, is readable and contains data
761
+ return file_exists($feedPath) && is_readable($feedPath) && filesize($feedPath) > 0;
762
+ }
763
+
764
+ protected function _streamCacheFileToBrowser($exitAfterStream = true)
765
+ {
766
+ $this->_sendHeader();
767
+
768
+ $feedPath = $this->_getFeedPath();
769
+
770
+ readfile($feedPath);
771
+
772
+ if ($exitAfterStream)
773
+ {
774
+ exit;
775
+ }
776
+ }
777
+
778
+ /**
779
+ * @param int $type_id
780
+ * @param array $args
781
+ * @return Sooqr_Feed_Model_Map_Product_Abstract
782
+ */
783
+ protected function _getProductMapModel($typeId, $args = array())
784
+ {
785
+ $params = array(
786
+ 'store_code' => $this->_sCurrentStoreCode,
787
+ 'store_id' => $this->_iCurrentStoreId,
788
+ 'website_id' => $this->_iCurrentWebsiteId,
789
+ );
790
+
791
+ $isAssoc = isset($args['is_assoc']) && $args['is_assoc'] ? true : false;
792
+
793
+ switch ($typeId)
794
+ {
795
+ case 'simple':
796
+ if ($isAssoc)
797
+ {
798
+ $oProductMap = Mage::getModel('feed/map_product_associated', $params);
799
+ }
800
+ else
801
+ {
802
+ $oProductMap = Mage::getModel('feed/map_product_simple', $params);
803
+ }
804
+ break;
805
+
806
+ case 'abstract':
807
+ case 'configurable':
808
+ case 'bundle':
809
+ case 'downloadable':
810
+ case 'grouped':
811
+ case 'virtual':
812
+ $oProductMap = Mage::getModel('feed/map_product_'.$typeId, $params);
813
+ break;
814
+
815
+ default:
816
+ return null;
817
+ }
818
+
819
+ return $oProductMap;
820
+ }
821
+
822
+ /**
823
+ * Returns the cached attribute object for the specifies attribute code
824
+ * @param unknown_type $code
825
+ * @return boolean
826
+ */
827
+ public function getAttribute($code)
828
+ {
829
+ if (isset($this->_aAttributes[$code]))
830
+ {
831
+ return $this->_aAttributes[$code];
832
+ }
833
+
834
+ return false;
835
+ }
836
+
837
+ public function getTools()
838
+ {
839
+ return Mage::getSingleton('feed/tools');
840
+ }
841
+
842
+ /**
843
+ * General logging method
844
+ *
845
+ * @param string $msg
846
+ * @param integer $level
847
+ */
848
+ public function log($msg, $level = null)
849
+ {
850
+ if (is_null($level))
851
+ {
852
+ $level = Zend_Log::INFO;
853
+ }
854
+
855
+ $m = memory_get_usage();
856
+ $units = array('b', 'Kb', 'Mb', 'Gb', 'Tb', 'Pb');
857
+ $mem = @round($m / pow(1024, ($i = floor(log($m, 1024)))), 2).' '.$units[$i];
858
+ $msg = sprintf('(mem %4.2f %s) ', $mem, $units[$i]).$msg;
859
+
860
+ Mage::log($msg, $level, $this->getData('log_filename'), $this->getData('force_log'));
861
+ }
862
+
863
+ protected function _addProductTypeToFilter($collection)
864
+ {
865
+ $allProductTypes = array(
866
+ Mage_Catalog_Model_Product_Type::TYPE_BUNDLE,
867
+ Mage_Catalog_Model_Product_Type::TYPE_CONFIGURABLE,
868
+ Mage_Downloadable_Model_Product_Type::TYPE_DOWNLOADABLE,
869
+ Mage_Catalog_Model_Product_Type::TYPE_GROUPED,
870
+ Mage_Catalog_Model_Product_Type::TYPE_SIMPLE,
871
+ Mage_Catalog_Model_Product_Type::TYPE_VIRTUAL,
872
+ );
873
+ $configedTypes = $this->getConfigVar('product_types');
874
+ $configedTypes = explode(',', $configedTypes);
875
+ $disabledTypes = array_diff($allProductTypes, $configedTypes);
876
+
877
+ // Check if we should disable specific types
878
+ if (count($disabledTypes) > 0)
879
+ {
880
+ $collection->addAttributeToFilter('type_id', array('nin' => $disabledTypes));
881
+ }
882
+
883
+ return $collection;
884
+ }
885
+
886
+ protected function _stopOnException(Exception $e)
887
+ {
888
+ Mage::log('Exception: '.$e->getMessage(), null, self::LOGFILE);
889
+
890
+ if ($this->getCliMode())
891
+ {
892
+ printf('Fatal error during script execution: ');
893
+ echo $e->getMessage()."\n";
894
+ }
895
+ else
896
+ {
897
+ header('HTTP/1.1 500 Internal Server Error', true, 500);
898
+ echo $e->getMessage()."\n";
899
+ }
900
+
901
+ die;
902
+ }
903
+
904
  }
app/code/community/Sooqr/Feed/Model/Map/Page/Abstract.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * NOTICE OF LICENSE
5
+ *
6
+ * This source file is subject to the Open Software License (OSL 3.0)
7
+ * that is bundled with this package in the file LICENSE.txt.
8
+ * It is also available through the world-wide-web at this URL:
9
+ * http://opensource.org/licenses/osl-3.0.php
10
+ *
11
+ * @category Sooqr
12
+ * @package Sooqr_Feed
13
+ * @copyright Copyright (c) 2011 RocketWeb (http://rocketweb.com)
14
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
15
+ * @author RocketWeb
16
+ */
17
+
18
+ class Sooqr_Feed_Model_Map_Page_Abstract extends Varien_Object
19
+ {
20
+
21
+
22
+ public function initialize()
23
+ {
24
+
25
+
26
+ }
27
+ }
app/code/community/Sooqr/Feed/Model/Map/Product/Abstract.php CHANGED
@@ -1,819 +1,848 @@
1
- <?php
2
-
3
- /**
4
- * NOTICE OF LICENSE
5
- *
6
- * This source file is subject to the Open Software License (OSL 3.0)
7
- * that is bundled with this package in the file LICENSE.txt.
8
- * It is also available through the world-wide-web at this URL:
9
- * http://opensource.org/licenses/osl-3.0.php
10
- *
11
- * @category Sooqr
12
- * @package Sooqr_Feed
13
- * @copyright Copyright (c) 2011 RocketWeb (http://rocketweb.com)
14
- * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
15
- * @author RocketWeb
16
- */
17
-
18
- class Sooqr_Feed_Model_Map_Product_Abstract extends Varien_Object
19
- {
20
- protected $_field_map = null;
21
- protected $skip = false;
22
- protected $_cache_gb_category = null;
23
- protected $_attributeSetModel;
24
-
25
- public function initialize()
26
- {
27
- $this->setData('store_currency_code', Mage::app()->getStore($this->getData('store_code'))->getCurrentCurrencyCode());
28
- $this->setData('images_url_prefix', Mage::app()->getStore($this->getData('store_id'))->getBaseUrl(Mage_Core_Model_Store::URL_TYPE_MEDIA, false).'catalog/product');
29
- $this->setData('images_path_prefix', Mage::getSingleton('catalog/product_media_config')->getBaseMediaPath());
30
-
31
- $this->_attributeSetModel = Mage::getModel('eav/entity_attribute_set');
32
-
33
- return $this;
34
- }
35
-
36
- public function map()
37
- {
38
- $this->_beforeMap();
39
- $rows = $this->_map();
40
- $this->_afterMap($rows);
41
- return $rows;
42
- }
43
-
44
- public function _beforeMap()
45
- {
46
- return $this;
47
- }
48
-
49
- public function _afterMap($rows)
50
- {
51
- return $this;
52
- }
53
-
54
- /**
55
- * Forms product's data row.
56
- * [column] => [value]
57
- *
58
- * @return array
59
- */
60
- protected function _map()
61
- {
62
- $fields = array();
63
-
64
- foreach ($this->_field_map as $column => $arr)
65
- {
66
- $fields[$column] = $this->mapField($column);
67
- }
68
-
69
- // Add the magento store identifier to each product
70
- $fields['magento_store'] = $this->getData('store_code');
71
-
72
- // Determine the attribute set name
73
- $this->_attributeSetModel->load($this->getProduct()->getAttributeSetId());
74
- $fields['attribute_set'] = $this->_attributeSetModel->getAttributeSetName();
75
-
76
- // Add user defined attributes
77
- if ($this->getConfigVar('export_all_user_attributes') == 1)
78
- {
79
- $oProduct = $this->getProduct();
80
-
81
- // Load only user defined attribute
82
- $aAttributes = Mage::getResourceModel('eav/entity_attribute_collection')
83
- ->addFieldToFilter('is_user_defined', 1)
84
- ->setEntityTypeFilter($oProduct->getResource()->getTypeId())
85
- ->setAttributeSetFilter($oProduct->getAttributeSetId())
86
- ->load();
87
- if (count($aAttributes))
88
- {
89
- foreach ($aAttributes as $oAttribute)
90
- {
91
- $fieldIndex = strtolower(preg_replace('/[^0-9a-z_]+/UiS', '', $oAttribute->attribute_code));
92
- if (preg_match('/^[0-9]/S', $fieldIndex))
93
- {
94
- $fieldIndex = 'n'.$fieldIndex;
95
- }
96
-
97
- $fields['sqr:'.$fieldIndex] = $this->mapSooqrAttribute($oAttribute);
98
- }
99
- }
100
- }
101
-
102
- // Add the category path to the variable system
103
- $iCategories = 0;
104
- $aCats = $this->getGenerator()->getCategories($this->getProduct());
105
- foreach ($aCats as $iIndex => $sCatName)
106
- {
107
- // Maximum category depth is 3 levels
108
- if ($iIndex >= 4)
109
- {
110
- break;
111
- }
112
- if (strlen($sCatName))
113
- {
114
- $fields['category'.$iCategories++] = $sCatName;
115
- }
116
- }
117
-
118
- return array($fields);
119
- }
120
-
121
- /**
122
- * @param string $column
123
- * @return string
124
- */
125
- protected function mapField($column)
126
- {
127
- $value = "";
128
- if (!isset($this->_field_map[$column]))
129
- return $value;
130
-
131
- $arr = $this->_field_map[$column];
132
- $args = array('map' => $arr);
133
-
134
- /* Column methods are required in a few cases.
135
- e.g. When child needs to get value from parent first. Further if value is empy takes value from it's own mapField* method.
136
- Can loop infinitely if misused.
137
- */
138
- $method = 'mapField'.$this->_camelize($column);
139
- if (method_exists($this, $method))
140
- {
141
- $value = $this->$method($args);
142
- }
143
- else
144
- {
145
- $value = $this->getFieldValue($args);
146
- }
147
-
148
- return $value;
149
- }
150
-
151
- /**
152
- * Gets value either from directive method or attribute method.
153
- * @param array $args
154
- * @return mixed
155
- */
156
- public function getFieldValue($args = array())
157
- {
158
- $arr = $args['map'];
159
-
160
- if ($this->getConfig()->isDirective($arr['attribute'], $this->getStoreId()))
161
- {
162
- $method = 'mapDirective'.$this->_camelize(str_replace('sqr_directive_', '', $arr['attribute']));
163
- if (method_exists($this, $method))
164
- $value = $this->$method($args);
165
- else
166
- $value = "";
167
- }
168
- else
169
- {
170
- $method = 'mapAttribute'.$this->_camelize($arr['attribute']);
171
- if (method_exists($this, $method))
172
- {
173
- $value = $this->$method($args);
174
- }
175
- else
176
- {
177
- $value = $this->mapAttribute($args);
178
- }
179
- }
180
-
181
- return $value;
182
- }
183
-
184
-
185
- /**
186
- * Process any other attribute.
187
- * @param array $params
188
- * @return string
189
- */
190
- protected function mapSooqrAttribute($oAttribute, $oProduct = null)
191
- {
192
- if (is_null($oProduct))
193
- {
194
- $oProduct = $this->getProduct();
195
- }
196
-
197
- if ($oAttribute === false)
198
- {
199
- Mage::throwException(sprintf('Couldn\'t find attribute \'%s\'.', $oAttribute->attribute_code));
200
- }
201
-
202
- $fieldData = $this->getAttributeValue($oProduct, $oAttribute);
203
-
204
- return $this->cleanField($fieldData);
205
- }
206
-
207
- /**
208
- * Process any other attribute.
209
- * @param array $params
210
- * @return string
211
- */
212
- protected function mapAttribute($params = array())
213
- {
214
- $map = $params['map'];
215
- $product = $this->getProduct();
216
- $fieldData = '';
217
-
218
- $attribute = $this->getGenerator()->getAttribute($map['attribute']);
219
- if ($attribute === false)
220
- {
221
- Mage::throwException(sprintf('Couldn\'t find attribute \'%s\'.', $map['attribute']));
222
- }
223
-
224
- $fieldData = $this->getAttributeValue($product, $attribute);
225
- $fieldData = $this->cleanField($fieldData);
226
-
227
- return $fieldData;
228
- }
229
-
230
- /**
231
- * @param array $params
232
- * @return string
233
- */
234
- protected function mapDirectiveId($params = array())
235
- {
236
- $map = $params['map'];
237
- $product = $this->getProduct();
238
- /* @var $product Mage_Catalog_Model_Product */
239
- $fieldData = "";
240
-
241
- $fieldData = $this->getProduct()->getId();
242
- $fieldData .= '_'.preg_replace('/[^a-zA-Z0-9]/', '', $this->getStoreCode());
243
-
244
- $fieldData = $this->cleanField($fieldData);
245
- return $fieldData;
246
- }
247
-
248
- /**
249
- * @param array $params
250
- * @return string
251
- */
252
- protected function mapDirectiveUrl($params = array())
253
- {
254
- $map = $params['map'];
255
- $product = $this->getProduct();
256
- $fieldData = '';
257
-
258
- if (count($product->getCategoryIds()) > 0)
259
- {
260
- $fieldData = sprintf('%s%s',
261
- Mage::app()->getStore($this->getData('store_id'))->getBaseUrl(Mage_Core_Model_Store::URL_TYPE_LINK),
262
- $product->getUrlPath());
263
- }
264
- else
265
- {
266
- // No category assigned to product => no url rewrite.
267
- $fieldData = $product->getProductUrl();
268
- }
269
-
270
- return $fieldData;
271
- }
272
-
273
- /**
274
- * @param array $params
275
- * @return string
276
- */
277
- protected function mapDirectiveImageLink($params = array())
278
- {
279
- $map = $params['map'];
280
- $product = $this->getProduct();
281
- /* @var $product Mage_Catalog_Model_Product */
282
- $fieldData = "";
283
-
284
- $image = $product->getData('image');
285
- if ($image != 'no_selection' && $image != "")
286
- $fieldData = (string)Mage::helper('catalog/image')->init($product, 'image')->resize(120);
287
- else
288
- $fieldData = '';
289
- return $fieldData;
290
- }
291
-
292
- /**
293
- * @param array $params
294
- * @return string
295
- */
296
- protected function mapDirectiveAdditionalImageLink($params = array())
297
- {
298
- $map = $params['map'];
299
- $product = $this->getProduct();
300
- /* @var $product Mage_Catalog_Model_Product */
301
- $fieldData = "";
302
-
303
- if (($base_image = $product->getData('image')) != "")
304
- $base_image = $this->getData('images_url_prefix') . $product->getData('image');
305
- $urls = array();
306
- $c = 0;
307
- $media_gal_imgs = $product->getMediaGalleryImages();
308
- if (is_array($media_gal_imgs) || $media_gal_imgs instanceof Varien_Data_Collection)
309
- {
310
- foreach ($product->getMediaGalleryImages() as $galImage)
311
- {
312
- if (++$c > 10)
313
- break;
314
- // Skip base image.
315
- if (strcmp($base_image, $galImage->getUrl()) == 0)
316
- continue;
317
- $urls[] = $galImage->getUrl();
318
- }
319
- }
320
- $fieldData = implode(",", $urls);
321
- return $fieldData;
322
- }
323
-
324
- /**
325
- * @param array $params
326
- * @return string
327
- */
328
- protected function mapDirectiveNormalPrice($params = array())
329
- {
330
- $map = $params['map'];
331
- $product = $this->getProduct();
332
- /* @var $product Mage_Catalog_Model_Product */
333
- $fieldData = "";
334
-
335
- $helper = Mage::helper('feed/tax');
336
- $priceIncludesTax = ( $helper->priceIncludesTax($this->getStoreId()) ? true : false);
337
-
338
- $includingTax = true;
339
- $price = $helper->getPrice($product, $this->getPrice(), $includingTax, false, false, null, $this->getStoreId(), $priceIncludesTax);
340
- $fieldData = $price;
341
-
342
- $fieldData = $this->cleanField($fieldData);
343
- if ($fieldData <= 0) {
344
- if ($this->getConfigVar('log_skip'))
345
- {
346
- $this->log(sprintf("product id %d product sku %s, skipped - product has price 0 = '%s'.", $this->getProduct()->getId(), $this->getProduct()->getSku(), $fieldData));
347
- }
348
- $this->skip = true;
349
- }
350
- return $fieldData;
351
- }
352
-
353
- public function getPrice()
354
- {
355
- return $this->getProduct()->getPrice();
356
- }
357
-
358
- public function calcMinimalPrice($product)
359
- {
360
- return $product->getMinimalPrice();
361
- }
362
-
363
- /**
364
- * @param array $params
365
- * @return string
366
- */
367
- protected function mapDirectivePrice($params = array())
368
- {
369
- $map = $params['map'];
370
- $product = $this->getProduct();
371
- /* @var $product Mage_Catalog_Model_Product */
372
- $fieldData = "";
373
- if ($product->getSpecialPrice() == 0)
374
- {
375
- // Return the normal price
376
- return $this->mapDirectiveNormalPrice($params);
377
- }
378
-
379
- /*$helper = Mage::helper('feed/tax');
380
- $priceIncludesTax = ( $helper->priceIncludesTax($this->getStoreId()) ? true : false);
381
- $includingTax = true;
382
- $price = $helper->getPrice($product, $this->getSpecialPrice(), $includingTax, false, false, null, $this->getStoreId(), $priceIncludesTax);*/
383
- $price = $product->getFinalPrice();
384
- $fieldData = $price;
385
-
386
- $fieldData = $this->cleanField($fieldData);
387
- return $fieldData;
388
- }
389
-
390
- public function getSpecialPrice()
391
- {
392
- return $this->getProduct()->getSpecialPrice();
393
- }
394
-
395
- public function hasSpecialPrice()
396
- {
397
- $has = false;
398
- $product = $this->getProduct();
399
-
400
- if ($this->getSpecialPrice() <= 0)
401
- return $has;
402
- if (is_empty_date($product->getSpecialFromDate()))
403
- return $has;
404
-
405
- $cDate = Mage::app()->getLocale()->date(null, null, Mage::app()->getLocale()->getDefaultLocale());
406
- $timezone = Mage::app()->getStore($this->getStoreId())->getConfig(Mage_Core_Model_Locale::XML_PATH_DEFAULT_TIMEZONE);
407
-
408
- $fromDate = new Zend_Date(null, null, Mage::app()->getLocale()->getDefaultLocale());
409
- if ($timezone) $fromDate->setTimezone($timezone);
410
- $fromDate->setDate(substr($product->getSpecialFromDate(), 0, 10), 'yyyy-MM-dd');
411
- $fromDate->setTime(substr($product->getSpecialFromDate(), 11, 8), 'HH:mm:ss');
412
-
413
- $toDate = new Zend_Date(null, null, Mage::app()->getLocale()->getDefaultLocale());
414
- if (!is_empty_date($product->getSpecialToDate())) {
415
- if ($timezone) $toDate->setTimezone($timezone);
416
- $toDate->setDate(substr($product->getSpecialToDate(), 0, 10), 'yyyy-MM-dd');
417
- $toDate->setTime('23:59:59', 'HH:mm:ss');
418
- } else {
419
- if ($timezone) $toDate->setTimezone($timezone);
420
- $toDate->setDate($cDate->toString('yyyy-MM-dd'), 'yyyy-MM-dd');
421
- $toDate->setTime('23:59:59', 'HH:mm:ss');
422
- $toDate->add(7, Zend_Date::DAY);
423
- }
424
-
425
- if (($fromDate->compare($cDate) == -1
426
- || $fromDate->compare($cDate) == 0)
427
- && ($toDate->compare($cDate) == 1
428
- || $toDate->compare($cDate) == 0))
429
- {
430
- $has = true;
431
- }
432
- return $has;
433
- }
434
-
435
- protected function mapDirectiveSalePriceEffectiveDate($params = array())
436
- {
437
- $map = $params['map'];
438
- $product = $this->getProduct();
439
- /* @var $product Mage_Catalog_Model_Product */
440
- $fieldData = "";
441
- if (!$this->hasSpecialPrice())
442
- return $fieldData;
443
-
444
- $cDate = Mage::app()->getLocale()->date(null, null, Mage::app()->getLocale()->getDefaultLocale());
445
- $timezone = Mage::app()->getStore($this->getStoreId())->getConfig(Mage_Core_Model_Locale::XML_PATH_DEFAULT_TIMEZONE);
446
-
447
- $fromDate = new Zend_Date(null, null, Mage::app()->getLocale()->getDefaultLocale());
448
- if ($timezone) $fromDate->setTimezone($timezone);
449
- $fromDate->setDate(substr($product->getSpecialFromDate(), 0, 10), 'yyyy-MM-dd');
450
- $fromDate->setTime(substr($product->getSpecialFromDate(), 11, 8), 'HH:mm:ss');
451
-
452
- $toDate = new Zend_Date(null, null, Mage::app()->getLocale()->getDefaultLocale());
453
- if (!is_empty_date($product->getSpecialToDate())) {
454
- if ($timezone) $toDate->setTimezone($timezone);
455
- $toDate->setDate(substr($product->getSpecialToDate(), 0, 10), 'yyyy-MM-dd');
456
- $toDate->setTime('23:59:59', 'HH:mm:ss');
457
- } else {
458
- if ($timezone) $toDate->setTimezone($timezone);
459
- $toDate->setDate($cDate->toString('yyyy-MM-dd'), 'yyyy-MM-dd');
460
- $toDate->setTime('23:59:59', 'HH:mm:ss');
461
- $toDate->add(7, Zend_Date::DAY);
462
- }
463
-
464
- $fieldData = $fromDate->toString(Zend_Date::ISO_8601)."/".$toDate->toString(Zend_Date::ISO_8601);
465
- return $fieldData;
466
- }
467
-
468
- protected function mapDirectiveCurrency($params = array())
469
- {
470
- $map = $params['map'];
471
- $product = $this->getProduct();
472
- /* @var $product Mage_Catalog_Model_Product */
473
- $fieldData = "";
474
-
475
- $fieldData = $this->getData('store_currency_code');
476
-
477
- return $fieldData;
478
- }
479
-
480
- protected function mapDirectiveAvailability($params = array())
481
- {
482
- $map = $params['map'];
483
- $product = $this->getProduct();
484
- /* @var $product Mage_Catalog_Model_Product */
485
- $fieldData = "";
486
-
487
- $default_value = isset($map['default_value']) ? $map['default_value'] : "";
488
- if ($default_value != "")
489
- {
490
- $stock_status = $default_value;
491
- $stock_status = trim(strtolower($stock_status));
492
-
493
- if (array_search($stock_status, $this->getConfig()->getAllowedStockStatuses()) === false)
494
- $stock_status = $this->getConfig()->getOutOfStockStatus();
495
-
496
- $fieldData = $stock_status;
497
- $fieldData = $this->cleanField($fieldData);
498
- return $fieldData;
499
- }
500
-
501
- $fieldData = $this->getConfig()->getOutOfStockStatus();
502
-
503
- $stockItem = Mage::getModel('cataloginventory/stock_item');
504
- $stockItem->setStoreId($this->getStoreId());
505
- $stockItem->getResource()->loadByProductId($stockItem, $product->getId());
506
- $stockItem->setOrigData();
507
-
508
- if ($stockItem->getId() && $stockItem->getIsInStock())
509
- {
510
- $fieldData = $this->getConfig()->getInStockStatus();
511
- }
512
-
513
- return $fieldData;
514
- }
515
-
516
- protected function mapDirectiveCondition($params = array())
517
- {
518
- $map = $params['map'];
519
- $product = $this->getProduct();
520
- /* @var $product Mage_Catalog_Model_Product */
521
- $fieldData = "";
522
-
523
- // only default value.
524
- $default_value = isset($map['default_value']) ? $map['default_value'] : "";
525
- $default_value = trim(strtolower($default_value));
526
- if (array_search($default_value, $this->getConfig()->getAllowedConditions()) === false)
527
- {
528
- $default_value = $this->getConfig()->getConditionNew();
529
- }
530
- $fieldData = $default_value;
531
-
532
- $fieldData = $this->cleanField($fieldData);
533
- return $fieldData;
534
- }
535
-
536
- protected function mapDirectivePaymentAccepted($params = array())
537
- {
538
- $map = $params['map'];
539
- $product = $this->getProduct();
540
- /* @var $product Mage_Catalog_Model_Product */
541
- $fieldData = "";
542
-
543
- $payment_accepted = $this->getConfig()->getMultipleSelectVar('payment_accepted', $this->getStoreId(), 'columns');
544
- $payment_accepted = implode(",", $payment_accepted);
545
- $fieldData = $payment_accepted;
546
-
547
- $fieldData = $this->cleanField($fieldData);
548
- return $fieldData;
549
- }
550
-
551
- /**
552
- * @param array $params
553
- * @return string
554
- */
555
- protected function mapAttributeDescription($params = array())
556
- {
557
- $map = $params['map'];
558
- $product = $this->getProduct();
559
- /* @var $product Mage_Catalog_Model_Product */
560
- $fieldData = "";
561
-
562
- $description_attribute = $this->getGenerator()->getAttribute($map['attribute']);
563
- if ($description_attribute === false)
564
- Mage::throwException(sprintf('Couldn\'t find attribute \'%s\'.', $map['attribute']));
565
-
566
- $description = $this->getAttributeValue($product, $description_attribute);
567
- $description = $this->cleanField($description);
568
- $max_len = (($max_len = $this->getConfigVar('max_description_length')) > 10000 ? 10000 : $max_len );
569
- $remainder = "";
570
- if ($max_len > 0)
571
- $description = Mage::helper('core/string')->truncate($description, $max_len, '', $remainder, false);
572
-
573
- $fieldData = $description;
574
-
575
- $fieldData = $this->cleanField($fieldData);
576
- return $fieldData;
577
- }
578
-
579
- /**
580
- * @param array $params
581
- * @return string
582
- */
583
- protected function mapAttributeWeight($params = array())
584
- {
585
- $map = $params['map'];
586
- $product = $this->getProduct();
587
- /* @var $product Mage_Catalog_Model_Product */
588
- $fieldData = "";
589
-
590
- $weight_attribute = $this->getGenerator()->getAttribute($map['attribute']);
591
- if ($weight_attribute === false)
592
- Mage::throwException(sprintf('Couldn\'t find attribute \'%s\'.', $map['attribute']));
593
-
594
- $weight = $this->getAttributeValue($product, $weight_attribute);
595
- if ($weight != "")
596
- $weight .= ' '.$this->getConfigVar('weight_unit_measure', 'columns');
597
-
598
- $fieldData = $weight;
599
-
600
- $fieldData = $this->cleanField($fieldData);
601
- return $fieldData;
602
- }
603
-
604
- public function mapFieldProductType($params = array())
605
- {
606
- $args = array('map' => $params['map']);
607
- $value = "";
608
-
609
- $map_by_category = $this->getConfig()->getMapCategorySorted('product_type_by_category', $this->getStoreId());
610
- $category_ids = $this->getProduct()->getCategoryIds();
611
- if (!empty($category_ids) && count($map_by_category) > 0)
612
- {
613
- foreach ($map_by_category as $arr)
614
- {
615
- if (array_search($arr['category'], $category_ids) !== false)
616
- {
617
- $value = $arr['value'];
618
- break;
619
- }
620
- }
621
- }
622
-
623
- if ($value != "")
624
- return html_entity_decode($value);
625
-
626
- $value = $this->getFieldValue($args);
627
-
628
- return html_entity_decode($value);
629
- }
630
-
631
- protected function cleanField($field)
632
- {
633
- if (is_array($field))
634
- {
635
- foreach ($field as &$value)
636
- {
637
- $value = $this->cleanFieldValue($value);
638
- unset($value);
639
- }
640
- }
641
- else
642
- {
643
- $field = $this->cleanFieldValue($field);
644
- }
645
-
646
- return $field;
647
- }
648
-
649
- /**
650
- * Cleans field by Google Base specs.
651
- *
652
- * @param string $field
653
- * @return string
654
- */
655
- protected function cleanFieldValue($field)
656
- {
657
- $field = strtr($field, array(
658
- "\"" => " ",
659
- "\t" => " ",
660
- "\n" => " ",
661
- "\r" => " ",
662
- ));
663
-
664
- $field = strip_tags($field);
665
- $field = preg_replace('/\s\s+/', ' ', $field);
666
- $field = str_replace(PHP_EOL, "", $field);
667
- $field = trim($field);
668
-
669
- return $field;
670
- }
671
-
672
- /**
673
- * @param Mage_Catalog_Model_Product $product
674
- * @return bool
675
- */
676
- protected function hasImage($product)
677
- {
678
- $image = $product->getData('image');
679
- if ($image != 'no_selection' && $image != "")
680
- {
681
- if (!file_exists($this->getData('images_path_prefix').$image))
682
- {
683
- return false;
684
- }
685
- }
686
- else
687
- {
688
- return false;
689
- }
690
- return true;
691
- }
692
-
693
- /**
694
- * @param Mage_Catalog_Model_Product $product
695
- * @return Sooqr_Feed_Model_Map_Product_Abstract
696
- */
697
- public function checkSkipSubmission()
698
- {
699
- return $this;
700
- }
701
-
702
- public function getAttributeValue($oProduct, $oAttribute)
703
- {
704
- if ($oAttribute->getFrontendInput() == 'select'
705
- || $oAttribute->getFrontendInput() == 'multiselect')
706
- {
707
- if (!is_null($oProduct->getResource()->getAttribute($oAttribute->getAttributeCode())))
708
- {
709
- $value = $oProduct->getAttributeText($oAttribute->attribute_code);
710
- }
711
-
712
- // $value = $this->getAttributeSelectValue($product, $attribute);
713
- }
714
- else
715
- {
716
- $value = $oProduct->getData($oAttribute->getAttributeCode());
717
- }
718
-
719
- return $value;
720
- }
721
-
722
- /**
723
- * Gets option text value from product for attributes with frontend_type select.
724
- * Multiselect values are by default imploded with comma.
725
- * By default gets option text from admin store (recommended - english values in feed).
726
- *
727
- * @param Mage_Catalog_Model_Product $product
728
- * @return string
729
- */
730
- protected function getAttributeSelectValue($product, $attribute, $store_id = null)
731
- {
732
- if (is_null($store_id))
733
- {
734
- $store_id = Mage_Core_Model_App::ADMIN_STORE_ID;
735
- }
736
- $pr = clone $product;
737
- $attr = clone $attribute;
738
- $attr->setStoreId($store_id);
739
- $ret = $attr ? $attr->getFrontend()->getValue($pr) : '';
740
- $ret = (strcasecmp($ret, "No") == 0 ? '' : $ret);
741
- return $ret;
742
- }
743
-
744
- /**
745
- * Fetch associated products ids of configurable product.
746
- * Filtered by current store_id (website_id) and status (enabled).
747
- *
748
- * @param Mage_Catalog_Model_Product $product
749
- * @param string $store_id
750
- * @return array | false
751
- */
752
- public function loadAssocIds($product, $store_id)
753
- {
754
- $assoc_ids = array();
755
- if ($product->getTypeId() != Mage_Catalog_Model_Product_Type::TYPE_CONFIGURABLE)
756
- {
757
- return false;
758
- }
759
-
760
- $as = $this->getTools()->getChildsIds($product->getId());
761
- if ($as === false)
762
- {
763
- return $assoc_ids;
764
- }
765
- $as = $this->getTools()->getProductInStoresIds($as);
766
- foreach ($as as $assocId => $s)
767
- {
768
- $attribute = $this->getGenerator()->getAttribute('status');
769
- $status = $this->getTools()->getProductAttributeValueBySql($attribute, $attribute->getBackendType(), $assocId, $store_id);
770
- if ($status != Mage_Catalog_Model_Product_Status::STATUS_ENABLED)
771
- {
772
- continue;
773
- }
774
-
775
- if (is_array($s)
776
- && array_search($store_id, $s) !== false)
777
- {
778
- $assoc_ids[] = $assocId;
779
- }
780
- }
781
- return $assoc_ids;
782
- }
783
-
784
- public function setFieldsMap($arr)
785
- {
786
- $this->_field_map = $arr;
787
- return $this;
788
- }
789
-
790
- public function isSkip() { return $this->skip; }
791
-
792
- /**
793
- * @return Sooqr_Feed_Model_Config
794
- */
795
- public function getConfig() { return $this->getGenerator()->getConfig(); }
796
-
797
- /**
798
- * @param string $key
799
- * @param string $section
800
- * @return mixed
801
- */
802
- public function getConfigVar($key, $section = 'feed')
803
- {
804
- return $this->getGenerator()->getConfigVar($key, null, $section);
805
- }
806
-
807
- /**
808
- * @return Sooqr_Feed_Model_Tools
809
- */
810
- public function getTools() { return $this->getGenerator()->getTools(); }
811
-
812
- public function log($msg, $level = null) { return $this->getGenerator()->log($msg, $level); }
813
-
814
- public function genUnsetData()
815
- {
816
- unset($this->_data);
817
- unset($this->_origData);
818
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
819
  }
1
+ <?php
2
+
3
+ /**
4
+ * NOTICE OF LICENSE
5
+ *
6
+ * This source file is subject to the Open Software License (OSL 3.0)
7
+ * that is bundled with this package in the file LICENSE.txt.
8
+ * It is also available through the world-wide-web at this URL:
9
+ * http://opensource.org/licenses/osl-3.0.php
10
+ *
11
+ * @category Sooqr
12
+ * @package Sooqr_Feed
13
+ * @copyright Copyright (c) 2011 RocketWeb (http://rocketweb.com)
14
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
15
+ * @author RocketWeb
16
+ */
17
+
18
+ class Sooqr_Feed_Model_Map_Product_Abstract extends Varien_Object
19
+ {
20
+ protected $_field_map = null;
21
+ protected $skip = false;
22
+ protected $_cache_gb_category = null;
23
+ protected $_attributeSetModel;
24
+
25
+ public function initialize()
26
+ {
27
+ $this->setData('store_currency_code', Mage::app()->getStore($this->getData('store_code'))->getCurrentCurrencyCode());
28
+ $this->setData('images_url_prefix', Mage::app()->getStore($this->getData('store_id'))->getBaseUrl(Mage_Core_Model_Store::URL_TYPE_MEDIA, false).'catalog/product');
29
+ $this->setData('images_path_prefix', Mage::getSingleton('catalog/product_media_config')->getBaseMediaPath());
30
+
31
+ $this->_attributeSetModel = Mage::getModel('eav/entity_attribute_set');
32
+
33
+ return $this;
34
+ }
35
+
36
+ public function map()
37
+ {
38
+ $this->_beforeMap();
39
+ $rows = $this->_map();
40
+ $this->_afterMap($rows);
41
+ return $rows;
42
+ }
43
+
44
+ public function _beforeMap()
45
+ {
46
+ return $this;
47
+ }
48
+
49
+ public function _afterMap($rows)
50
+ {
51
+ return $this;
52
+ }
53
+
54
+ /**
55
+ * Forms product's data row.
56
+ * [column] => [value]
57
+ *
58
+ * @return array
59
+ */
60
+ protected function _map()
61
+ {
62
+ $fields = array();
63
+
64
+ foreach ($this->_field_map as $column => $arr)
65
+ {
66
+ $fields[$column] = $this->mapField($column);
67
+ }
68
+
69
+ // Add the magento store identifier to each product
70
+ $fields['magento_store'] = $this->getData('store_code');
71
+ $fields['currency'] = $this->mapDirectiveCurrency();
72
+
73
+ // Determine the attribute set name
74
+ $this->_attributeSetModel->load($this->getProduct()->getAttributeSetId());
75
+ $fields['attribute_set'] = $this->_attributeSetModel->getAttributeSetName();
76
+
77
+ // Add user defined attributes
78
+ if ($this->getConfigVar('export_all_user_attributes') == 1)
79
+ {
80
+ $oProduct = $this->getProduct();
81
+
82
+ // Load only user defined attribute
83
+ $aAttributes = Mage::getResourceModel('eav/entity_attribute_collection')
84
+ ->addFieldToFilter('is_user_defined', 1)
85
+ ->setEntityTypeFilter($oProduct->getResource()->getTypeId())
86
+ ->setAttributeSetFilter($oProduct->getAttributeSetId())
87
+ ->load();
88
+ if (count($aAttributes))
89
+ {
90
+ foreach ($aAttributes as $oAttribute)
91
+ {
92
+ $fieldIndex = strtolower(preg_replace('/[^0-9a-z_]+/UiS', '', $oAttribute->attribute_code));
93
+ if (preg_match('/^[0-9]/S', $fieldIndex))
94
+ {
95
+ $fieldIndex = 'n'.$fieldIndex;
96
+ }
97
+
98
+ $fields['sqr:'.$fieldIndex] = $this->mapSooqrAttribute($oAttribute);
99
+ }
100
+ }
101
+ }
102
+
103
+ //add meta-keywords
104
+ $fields['tag_words'] = trim($this->getProduct()->meta_keyword, ' ,');
105
+
106
+ // Add stock
107
+ $stock_item = Mage::getModel('cataloginventory/stock_item')->loadByProduct($this->getProduct());
108
+ $fields['stock'] = $stock_item->getQty();
109
+
110
+ // Add stock status
111
+ $fields['in_stock'] = $stock_item->getIsInStock();
112
+ $fields['stock_status'] = $stock_item->getIsInStock() ? 'In Stock' : 'Out of Stock';
113
+
114
+ // Add producttype
115
+ $fields['product_object_type'] = $this->getProduct()->getTypeID();
116
+
117
+ // Add the category path to the variable system
118
+ $iCategories = 0;
119
+ $aCats = $this->getGenerator()->getCategories($this->getProduct(),
120
+ Sooqr_Feed_Model_Generator::GETCATEGORIES_ACTIVEONLY);
121
+ if (is_array($aCats))
122
+ {
123
+ foreach ($aCats as $iIndex => $sCatName)
124
+ {
125
+ // Maximum category depth is 10 levels
126
+ if ($iIndex >= 10)
127
+ {
128
+ break;
129
+ }
130
+ if (is_array($sCatName)
131
+ || strlen($sCatName))
132
+ {
133
+ $fields['category'.$iCategories++] = $sCatName;
134
+ }
135
+ }
136
+ }
137
+
138
+ // When we have no active categories, skip the product
139
+ if ($iCategories == 0)
140
+ {
141
+ $this->skip = true;
142
+ }
143
+
144
+ return array($fields);
145
+ }
146
+
147
+ /**
148
+ * @param string $column
149
+ * @return string
150
+ */
151
+ protected function mapField($column)
152
+ {
153
+ $value = "";
154
+ if (!isset($this->_field_map[$column]))
155
+ return $value;
156
+
157
+ $arr = $this->_field_map[$column];
158
+ $args = array('map' => $arr);
159
+
160
+ /* Column methods are required in a few cases.
161
+ e.g. When child needs to get value from parent first. Further if value is empy takes value from it's own mapField* method.
162
+ Can loop infinitely if misused.
163
+ */
164
+ $method = 'mapField'.$this->_camelize($column);
165
+ if (method_exists($this, $method))
166
+ {
167
+ $value = $this->$method($args);
168
+ }
169
+ else
170
+ {
171
+ $value = $this->getFieldValue($args);
172
+ }
173
+
174
+ return $value;
175
+ }
176
+
177
+ /**
178
+ * Gets value either from directive method or attribute method.
179
+ * @param array $args
180
+ * @return mixed
181
+ */
182
+ public function getFieldValue($args = array())
183
+ {
184
+ $arr = $args['map'];
185
+
186
+ if ($this->getConfig()->isDirective($arr['attribute'], $this->getStoreId()))
187
+ {
188
+ $method = 'mapDirective'.$this->_camelize(str_replace('sqr_directive_', '', $arr['attribute']));
189
+ if (method_exists($this, $method))
190
+ $value = $this->$method($args);
191
+ else
192
+ $value = "";
193
+ }
194
+ else
195
+ {
196
+ $method = 'mapAttribute'.$this->_camelize($arr['attribute']);
197
+ if (method_exists($this, $method))
198
+ {
199
+ $value = $this->$method($args);
200
+ }
201
+ else
202
+ {
203
+ $value = $this->mapAttribute($args);
204
+ }
205
+ }
206
+
207
+ return $value;
208
+ }
209
+
210
+
211
+ /**
212
+ * Process any other attribute.
213
+ * @param array $params
214
+ * @return string
215
+ */
216
+ protected function mapSooqrAttribute($oAttribute, $oProduct = null)
217
+ {
218
+ if (is_null($oProduct))
219
+ {
220
+ $oProduct = $this->getProduct();
221
+ }
222
+
223
+ if ($oAttribute === false)
224
+ {
225
+ Mage::throwException(sprintf('Couldn\'t find attribute \'%s\'.', $oAttribute->attribute_code));
226
+ }
227
+
228
+ $fieldData = $this->getAttributeValue($oProduct, $oAttribute);
229
+
230
+ return $this->cleanField($fieldData);
231
+ }
232
+
233
+ /**
234
+ * Process any other attribute.
235
+ * @param array $params
236
+ * @return string
237
+ */
238
+ protected function mapAttribute($params = array())
239
+ {
240
+ $map = $params['map'];
241
+ $product = $this->getProduct();
242
+ $fieldData = '';
243
+
244
+ $attribute = $this->getGenerator()->getAttribute($map['attribute']);
245
+ if ($attribute === false)
246
+ {
247
+ Mage::throwException(sprintf('Couldn\'t find attribute \'%s\'.', $map['attribute']));
248
+ }
249
+
250
+ $fieldData = $this->getAttributeValue($product, $attribute);
251
+ $fieldData = $this->cleanField($fieldData);
252
+
253
+ return $fieldData;
254
+ }
255
+
256
+ /**
257
+ * @param array $params
258
+ * @return string
259
+ */
260
+ protected function mapDirectiveId($params = array())
261
+ {
262
+ $map = $params['map'];
263
+ $product = $this->getProduct();
264
+ /* @var $product Mage_Catalog_Model_Product */
265
+ $fieldData = "";
266
+
267
+ $fieldData = $this->getProduct()->getId();
268
+ $fieldData .= '_'.preg_replace('/[^a-zA-Z0-9]/', '', $this->getStoreCode());
269
+
270
+ $fieldData = $this->cleanField($fieldData);
271
+ return $fieldData;
272
+ }
273
+
274
+ /**
275
+ * @param array $params
276
+ * @return string
277
+ */
278
+ protected function mapDirectiveUrl($params = array())
279
+ {
280
+ $map = $params['map'];
281
+ $product = $this->getProduct();
282
+ $fieldData = '';
283
+
284
+ if (count($product->getCategoryIds()) > 0)
285
+ {
286
+ $fieldData = sprintf('%s%s',
287
+ Mage::app()->getStore($this->getData('store_id'))->getBaseUrl(Mage_Core_Model_Store::URL_TYPE_LINK),
288
+ $product->getUrlPath());
289
+ }
290
+ else
291
+ {
292
+ // No category assigned to product => no url rewrite.
293
+ $fieldData = $product->getProductUrl();
294
+ }
295
+
296
+ return $fieldData;
297
+ }
298
+
299
+ /**
300
+ * @param array $params
301
+ * @return string
302
+ */
303
+ protected function mapDirectiveImageLink($params = array())
304
+ {
305
+ $map = $params['map'];
306
+ $product = $this->getProduct();
307
+ /* @var $product Mage_Catalog_Model_Product */
308
+ $fieldData = "";
309
+
310
+ $image = $product->getData('image');
311
+ if ($image != 'no_selection' && $image != "")
312
+ {
313
+ $fieldData = (string)Mage::helper('catalog/image')->init($product, 'small_image')->resize(Sooqr_Feed_Model_Generator::THUMBNAIL_WIDTH);
314
+ }
315
+ else
316
+ $fieldData = '';
317
+ return $fieldData;
318
+ }
319
+
320
+ /**
321
+ * @param array $params
322
+ * @return string
323
+ */
324
+ protected function mapDirectiveAdditionalImageLink($params = array())
325
+ {
326
+ $map = $params['map'];
327
+ $product = $this->getProduct();
328
+ /* @var $product Mage_Catalog_Model_Product */
329
+ $fieldData = "";
330
+
331
+ if (($base_image = $product->getData('image')) != "")
332
+ $base_image = $this->getData('images_url_prefix') . $product->getData('image');
333
+ $urls = array();
334
+ $c = 0;
335
+ $media_gal_imgs = $product->getMediaGalleryImages();
336
+ if (is_array($media_gal_imgs) || $media_gal_imgs instanceof Varien_Data_Collection)
337
+ {
338
+ foreach ($product->getMediaGalleryImages() as $galImage)
339
+ {
340
+ if (++$c > 10)
341
+ break;
342
+ // Skip base image.
343
+ if (strcmp($base_image, $galImage->getUrl()) == 0)
344
+ continue;
345
+ $urls[] = $galImage->getUrl();
346
+ }
347
+ }
348
+ $fieldData = implode(",", $urls);
349
+ return $fieldData;
350
+ }
351
+
352
+ /**
353
+ * @param array $params
354
+ * @return string
355
+ */
356
+ protected function mapDirectiveNormalPrice($params = array())
357
+ {
358
+ $map = $params['map'];
359
+ $product = $this->getProduct();
360
+ /* @var $product Mage_Catalog_Model_Product */
361
+ $fieldData = "";
362
+
363
+ $helper = Mage::helper('feed/tax');
364
+ $priceIncludesTax = ( $helper->priceIncludesTax($this->getStoreId()) ? true : false);
365
+
366
+ $includingTax = true;
367
+ $price = $helper->getPrice($product, $this->getPrice(), $includingTax, false, false, null, $this->getStoreId(), $priceIncludesTax);
368
+
369
+ // Optional currency conversion
370
+ $fieldData = Mage::helper('core')->currency($price, false, false);
371
+
372
+ if ($fieldData <= 0) {
373
+ if ($this->getConfigVar('log_skip'))
374
+ {
375
+ $this->log(sprintf("product id %d product sku %s, skipped - product has price 0 = '%s'.", $this->getProduct()->getId(), $this->getProduct()->getSku(), $fieldData));
376
+ }
377
+ $this->skip = true;
378
+ }
379
+ return $fieldData;
380
+ }
381
+
382
+ public function getPrice()
383
+ {
384
+ return $this->getProduct()->getPrice();
385
+ }
386
+
387
+ public function calcMinimalPrice($product)
388
+ {
389
+ return $product->getMinimalPrice();
390
+ }
391
+
392
+ /**
393
+ * @param array $params
394
+ * @return string
395
+ */
396
+ protected function mapDirectivePrice($params = array())
397
+ {
398
+ $map = $params['map'];
399
+ //$product = $this->getProduct();
400
+
401
+ return Mage::helper('core')->currency($this->getFinalPrice(), false, false);
402
+ }
403
+
404
+ protected function getFinalPrice()
405
+ {
406
+ $product = $this->getProduct();
407
+
408
+ return $product->getFinalPrice();
409
+ }
410
+
411
+ public function getSpecialPrice()
412
+ {
413
+ return $this->getProduct()->getSpecialPrice();
414
+ }
415
+
416
+ public function hasSpecialPrice()
417
+ {
418
+ $has = false;
419
+ $product = $this->getProduct();
420
+
421
+ if ($this->getSpecialPrice() <= 0)
422
+ return $has;
423
+ if (is_empty_date($product->getSpecialFromDate()))
424
+ return $has;
425
+
426
+ $cDate = Mage::app()->getLocale()->date(null, null, Mage::app()->getLocale()->getDefaultLocale());
427
+ $timezone = Mage::app()->getStore($this->getStoreId())->getConfig(Mage_Core_Model_Locale::XML_PATH_DEFAULT_TIMEZONE);
428
+
429
+ $fromDate = new Zend_Date(null, null, Mage::app()->getLocale()->getDefaultLocale());
430
+ if ($timezone) $fromDate->setTimezone($timezone);
431
+ $fromDate->setDate(substr($product->getSpecialFromDate(), 0, 10), 'yyyy-MM-dd');
432
+ $fromDate->setTime(substr($product->getSpecialFromDate(), 11, 8), 'HH:mm:ss');
433
+
434
+ $toDate = new Zend_Date(null, null, Mage::app()->getLocale()->getDefaultLocale());
435
+ if (!is_empty_date($product->getSpecialToDate())) {
436
+ if ($timezone) $toDate->setTimezone($timezone);
437
+ $toDate->setDate(substr($product->getSpecialToDate(), 0, 10), 'yyyy-MM-dd');
438
+ $toDate->setTime('23:59:59', 'HH:mm:ss');
439
+ } else {
440
+ if ($timezone) $toDate->setTimezone($timezone);
441
+ $toDate->setDate($cDate->toString('yyyy-MM-dd'), 'yyyy-MM-dd');
442
+ $toDate->setTime('23:59:59', 'HH:mm:ss');
443
+ $toDate->add(7, Zend_Date::DAY);
444
+ }
445
+
446
+ if (($fromDate->compare($cDate) == -1
447
+ || $fromDate->compare($cDate) == 0)
448
+ && ($toDate->compare($cDate) == 1
449
+ || $toDate->compare($cDate) == 0))
450
+ {
451
+ $has = true;
452
+ }
453
+ return $has;
454
+ }
455
+
456
+ protected function mapDirectiveSalePriceEffectiveDate($params = array())
457
+ {
458
+ $map = $params['map'];
459
+ $product = $this->getProduct();
460
+ /* @var $product Mage_Catalog_Model_Product */
461
+ $fieldData = "";
462
+ if (!$this->hasSpecialPrice())
463
+ return $fieldData;
464
+
465
+ $cDate = Mage::app()->getLocale()->date(null, null, Mage::app()->getLocale()->getDefaultLocale());
466
+ $timezone = Mage::app()->getStore($this->getStoreId())->getConfig(Mage_Core_Model_Locale::XML_PATH_DEFAULT_TIMEZONE);
467
+
468
+ $fromDate = new Zend_Date(null, null, Mage::app()->getLocale()->getDefaultLocale());
469
+ if ($timezone) $fromDate->setTimezone($timezone);
470
+ $fromDate->setDate(substr($product->getSpecialFromDate(), 0, 10), 'yyyy-MM-dd');
471
+ $fromDate->setTime(substr($product->getSpecialFromDate(), 11, 8), 'HH:mm:ss');
472
+
473
+ $toDate = new Zend_Date(null, null, Mage::app()->getLocale()->getDefaultLocale());
474
+ if (!is_empty_date($product->getSpecialToDate())) {
475
+ if ($timezone) $toDate->setTimezone($timezone);
476
+ $toDate->setDate(substr($product->getSpecialToDate(), 0, 10), 'yyyy-MM-dd');
477
+ $toDate->setTime('23:59:59', 'HH:mm:ss');
478
+ } else {
479
+ if ($timezone) $toDate->setTimezone($timezone);
480
+ $toDate->setDate($cDate->toString('yyyy-MM-dd'), 'yyyy-MM-dd');
481
+ $toDate->setTime('23:59:59', 'HH:mm:ss');
482
+ $toDate->add(7, Zend_Date::DAY);
483
+ }
484
+
485
+ $fieldData = $fromDate->toString(Zend_Date::ISO_8601)."/".$toDate->toString(Zend_Date::ISO_8601);
486
+ return $fieldData;
487
+ }
488
+
489
+ protected function mapDirectiveCurrency($params = array())
490
+ {
491
+ return $this->getData('store_currency_code');
492
+ }
493
+
494
+ protected function mapDirectiveAvailability($params = array())
495
+ {
496
+ $map = $params['map'];
497
+ $product = $this->getProduct();
498
+ /* @var $product Mage_Catalog_Model_Product */
499
+ $fieldData = "";
500
+
501
+ $default_value = isset($map['default_value']) ? $map['default_value'] : "";
502
+ if ($default_value != "")
503
+ {
504
+ $stock_status = $default_value;
505
+ $stock_status = trim(strtolower($stock_status));
506
+
507
+ if (array_search($stock_status, $this->getConfig()->getAllowedStockStatuses()) === false)
508
+ $stock_status = $this->getConfig()->getOutOfStockStatus();
509
+
510
+ $fieldData = $stock_status;
511
+ $fieldData = $this->cleanField($fieldData);
512
+ return $fieldData;
513
+ }
514
+
515
+ $fieldData = $this->getConfig()->getOutOfStockStatus();
516
+
517
+ $stockItem = Mage::getModel('cataloginventory/stock_item');
518
+ $stockItem->setStoreId($this->getStoreId());
519
+ $stockItem->getResource()->loadByProductId($stockItem, $product->getId());
520
+ $stockItem->setOrigData();
521
+
522
+ if ($stockItem->getId() && $stockItem->getIsInStock())
523
+ {
524
+ $fieldData = $this->getConfig()->getInStockStatus();
525
+ }
526
+
527
+ return $fieldData;
528
+ }
529
+
530
+ protected function mapDirectiveCondition($params = array())
531
+ {
532
+ $map = $params['map'];
533
+ $product = $this->getProduct();
534
+ /* @var $product Mage_Catalog_Model_Product */
535
+ $fieldData = "";
536
+
537
+ // only default value.
538
+ $default_value = isset($map['default_value']) ? $map['default_value'] : "";
539
+ $default_value = trim(strtolower($default_value));
540
+ if (array_search($default_value, $this->getConfig()->getAllowedConditions()) === false)
541
+ {
542
+ $default_value = $this->getConfig()->getConditionNew();
543
+ }
544
+ $fieldData = $default_value;
545
+
546
+ $fieldData = $this->cleanField($fieldData);
547
+ return $fieldData;
548
+ }
549
+
550
+ protected function mapDirectivePaymentAccepted($params = array())
551
+ {
552
+ $map = $params['map'];
553
+ $product = $this->getProduct();
554
+ /* @var $product Mage_Catalog_Model_Product */
555
+ $fieldData = "";
556
+
557
+ $payment_accepted = $this->getConfig()->getMultipleSelectVar('payment_accepted', $this->getStoreId(), 'columns');
558
+ $payment_accepted = implode(",", $payment_accepted);
559
+ $fieldData = $payment_accepted;
560
+
561
+ $fieldData = $this->cleanField($fieldData);
562
+ return $fieldData;
563
+ }
564
+
565
+ /**
566
+ * @param array $params
567
+ * @return string
568
+ */
569
+ protected function mapAttributeDescription($params = array())
570
+ {
571
+ $map = $params['map'];
572
+ $product = $this->getProduct();
573
+ /* @var $product Mage_Catalog_Model_Product */
574
+ $fieldData = "";
575
+
576
+ $description_attribute = $this->getGenerator()->getAttribute($map['attribute']);
577
+ if ($description_attribute === false)
578
+ Mage::throwException(sprintf('Couldn\'t find attribute \'%s\'.', $map['attribute']));
579
+
580
+ $description = $this->getAttributeValue($product, $description_attribute);
581
+ $description = $this->cleanField($description);
582
+ $max_len = (($max_len = $this->getConfigVar('max_description_length')) > 10000 ? 10000 : $max_len );
583
+ $remainder = "";
584
+ if ($max_len > 0)
585
+ $description = Mage::helper('core/string')->truncate($description, $max_len, '', $remainder, false);
586
+
587
+ $fieldData = $description;
588
+
589
+ $fieldData = $this->cleanField($fieldData);
590
+ return $fieldData;
591
+ }
592
+
593
+ /**
594
+ * @param array $params
595
+ * @return string
596
+ */
597
+ protected function mapAttributeWeight($params = array())
598
+ {
599
+ $map = $params['map'];
600
+ $product = $this->getProduct();
601
+ /* @var $product Mage_Catalog_Model_Product */
602
+ $fieldData = "";
603
+
604
+ $weight_attribute = $this->getGenerator()->getAttribute($map['attribute']);
605
+ if ($weight_attribute === false)
606
+ Mage::throwException(sprintf('Couldn\'t find attribute \'%s\'.', $map['attribute']));
607
+
608
+ $weight = $this->getAttributeValue($product, $weight_attribute);
609
+ if ($weight != "")
610
+ $weight .= ' '.$this->getConfigVar('weight_unit_measure', 'columns');
611
+
612
+ $fieldData = $weight;
613
+
614
+ $fieldData = $this->cleanField($fieldData);
615
+ return $fieldData;
616
+ }
617
+
618
+ protected function cleanField($field)
619
+ {
620
+ if (is_array($field))
621
+ {
622
+ foreach ($field as &$value)
623
+ {
624
+ $value = $this->cleanFieldValue($value);
625
+ unset($value);
626
+ }
627
+ }
628
+ else
629
+ {
630
+ $field = $this->cleanFieldValue($field);
631
+ }
632
+
633
+ return $field;
634
+ }
635
+
636
+ /**
637
+ * Cleans field by Google Base specs.
638
+ *
639
+ * @param string $field
640
+ * @return string
641
+ */
642
+ protected function cleanFieldValue($field)
643
+ {
644
+ if(is_array($field))
645
+ {
646
+ foreach($field as $i => $f)
647
+ {
648
+ $field[$i] = $this->cleanFieldValue($f);
649
+ }
650
+ return $field;
651
+ }
652
+ $field = strtr($field, array(
653
+ "\"" => " ",
654
+ "\t" => " ",
655
+ "\n" => " ",
656
+ "\r" => " ",
657
+ ));
658
+
659
+ $field = strip_tags($field);
660
+ $field = preg_replace('/\s\s+/', ' ', $field);
661
+ $field = str_replace(PHP_EOL, "", $field);
662
+ $field = trim($field);
663
+ $field = $this->stripInvalidXml($field);
664
+
665
+ return $field;
666
+ }
667
+
668
+ function stripInvalidXml($value)
669
+ {
670
+ $ret = "";
671
+ $current = null;
672
+ if (empty($value))
673
+ {
674
+ return $ret;
675
+ }
676
+
677
+ $value = iconv("UTF-8", "UTF-8//TRANSLIT", $value);
678
+ $value = iconv("UTF-8", "UTF-8//IGNORE", $value);
679
+
680
+ $length = strlen($value);
681
+ for ($i=0; $i < $length; $i++)
682
+ {
683
+ $current = ord($value{$i});
684
+ if (($current == 0x9) ||
685
+ ($current == 0xA) ||
686
+ ($current == 0xD) ||
687
+ (($current >= 0x20) && ($current <= 0xD7FF)) ||
688
+ (($current >= 0xE000) && ($current <= 0xFFFD)) ||
689
+ (($current >= 0x10000) && ($current <= 0x10FFFF)))
690
+ {
691
+ $ret .= chr($current);
692
+ }
693
+ else
694
+ {
695
+ $ret .= " ";
696
+ }
697
+ }
698
+ return $ret;
699
+ }
700
+
701
+ /**
702
+ * @param Mage_Catalog_Model_Product $product
703
+ * @return bool
704
+ */
705
+ protected function hasImage($product)
706
+ {
707
+ $image = $product->getData('image');
708
+ if ($image != 'no_selection' && $image != "")
709
+ {
710
+ if (!file_exists($this->getData('images_path_prefix').$image))
711
+ {
712
+ return false;
713
+ }
714
+ }
715
+ else
716
+ {
717
+ return false;
718
+ }
719
+ return true;
720
+ }
721
+
722
+ /**
723
+ * @param Mage_Catalog_Model_Product $product
724
+ * @return Sooqr_Feed_Model_Map_Product_Abstract
725
+ */
726
+ public function checkSkipSubmission()
727
+ {
728
+ return $this;
729
+ }
730
+
731
+ public function getAttributeValue($oProduct, $oAttribute)
732
+ {
733
+ if ($oAttribute->getFrontendInput() == 'select'
734
+ || $oAttribute->getFrontendInput() == 'multiselect')
735
+ {
736
+ if (!is_null($oProduct->getResource()->getAttribute($oAttribute->getAttributeCode())))
737
+ {
738
+ $value = $oProduct->getAttributeText($oAttribute->attribute_code);
739
+ }
740
+
741
+ // $value = $this->getAttributeSelectValue($product, $attribute);
742
+ }
743
+ else
744
+ {
745
+ $value = $oProduct->getData($oAttribute->getAttributeCode());
746
+ }
747
+
748
+ return $value;
749
+ }
750
+
751
+ /**
752
+ * Gets option text value from product for attributes with frontend_type select.
753
+ * Multiselect values are by default imploded with comma.
754
+ * By default gets option text from admin store (recommended - english values in feed).
755
+ *
756
+ * @param Mage_Catalog_Model_Product $product
757
+ * @return string
758
+ */
759
+ protected function getAttributeSelectValue($product, $attribute, $store_id = null)
760
+ {
761
+ if (is_null($store_id))
762
+ {
763
+ $store_id = Mage_Core_Model_App::ADMIN_STORE_ID;
764
+ }
765
+ $pr = clone $product;
766
+ $attr = clone $attribute;
767
+ $attr->setStoreId($store_id);
768
+ $ret = $attr ? $attr->getFrontend()->getValue($pr) : '';
769
+ $ret = (strcasecmp($ret, "No") == 0 ? '' : $ret);
770
+ return $ret;
771
+ }
772
+
773
+ /**
774
+ * Fetch associated products ids of configurable product.
775
+ * Filtered by current store_id (website_id) and status (enabled).
776
+ *
777
+ * @param Mage_Catalog_Model_Product $product
778
+ * @param string $store_id
779
+ * @return array | false
780
+ */
781
+ public function loadAssocIds($product, $store_id)
782
+ {
783
+ $assoc_ids = array();
784
+ if ($product->getTypeId() != Mage_Catalog_Model_Product_Type::TYPE_CONFIGURABLE)
785
+ {
786
+ return false;
787
+ }
788
+
789
+ $as = $this->getTools()->getChildsIds($product->getId());
790
+ if ($as === false)
791
+ {
792
+ return $assoc_ids;
793
+ }
794
+ $as = $this->getTools()->getProductInStoresIds($as);
795
+ foreach ($as as $assocId => $s)
796
+ {
797
+ $attribute = $this->getGenerator()->getAttribute('status');
798
+ $status = $this->getTools()->getProductAttributeValueBySql($attribute, $attribute->getBackendType(), $assocId, $store_id);
799
+ if ($status != Mage_Catalog_Model_Product_Status::STATUS_ENABLED)
800
+ {
801
+ continue;
802
+ }
803
+
804
+ if (is_array($s)
805
+ && array_search($store_id, $s) !== false)
806
+ {
807
+ $assoc_ids[] = $assocId;
808
+ }
809
+ }
810
+ return $assoc_ids;
811
+ }
812
+
813
+ public function setFieldsMap($arr)
814
+ {
815
+ $this->_field_map = $arr;
816
+ return $this;
817
+ }
818
+
819
+ public function isSkip() { return $this->skip; }
820
+
821
+ /**
822
+ * @return Sooqr_Feed_Model_Config
823
+ */
824
+ public function getConfig() { return $this->getGenerator()->getConfig(); }
825
+
826
+ /**
827
+ * @param string $key
828
+ * @param string $section
829
+ * @return mixed
830
+ */
831
+ public function getConfigVar($key, $section = 'feed')
832
+ {
833
+ return $this->getGenerator()->getConfigVar($key, null, $section);
834
+ }
835
+
836
+ /**
837
+ * @return Sooqr_Feed_Model_Tools
838
+ */
839
+ public function getTools() { return $this->getGenerator()->getTools(); }
840
+
841
+ public function log($msg, $level = null) { return $this->getGenerator()->log($msg, $level); }
842
+
843
+ public function genUnsetData()
844
+ {
845
+ unset($this->_data);
846
+ unset($this->_origData);
847
+ }
848
  }
app/code/community/Sooqr/Feed/Model/Map/Product/Associated.php CHANGED
@@ -1,235 +1,235 @@
1
- <?php
2
-
3
- /**
4
- * NOTICE OF LICENSE
5
- *
6
- * This source file is subject to the Open Software License (OSL 3.0)
7
- * that is bundled with this package in the file LICENSE.txt.
8
- * It is also available through the world-wide-web at this URL:
9
- * http://opensource.org/licenses/osl-3.0.php
10
- *
11
- * @category Sooqr
12
- * @package Sooqr_Feed
13
- * @copyright Copyright (c) 2011 RocketWeb (http://rocketweb.com)
14
- * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
15
- * @author RocketWeb
16
- */
17
-
18
- class Sooqr_Feed_Model_Map_Product_Associated extends Sooqr_Feed_Model_Map_Product_Abstract
19
- {
20
- /**
21
- * @param string $column
22
- * @return string
23
- */
24
- protected function mapField($column)
25
- {
26
- $value = parent::mapField($column);
27
- if ($value == "")
28
- {
29
- $value = $this->getParentMap()->mapField($column);
30
- }
31
-
32
- return $value;
33
- }
34
-
35
- public function mapFieldDescription($params = array())
36
- {
37
- $args = array('map' => $params['map']);
38
- $value = "";
39
-
40
- $value = $this->getCellValue($args);
41
- if ($value == "")
42
- $value = $this->getParentMap()->mapField('description');
43
-
44
- return $value;
45
- }
46
-
47
- public function mapFieldLink($params = array())
48
- {
49
- $args = array('map' => $params['map']);
50
- $product = $this->getProduct();
51
- $value = "";
52
-
53
- if ($product->isVisibleInSiteVisibility()) {
54
- $value = $this->getCellValue($args);
55
- } else {
56
- $value = $this->getParentMap()->mapField('link');
57
- if ($this->getConfigVar('associated_products_link_add_unique', 'columns'))
58
- $value = $this->addUrlUniqueParams($value, $product, $this->getParentMap()->getConfigurableAttributeCodes());
59
- }
60
-
61
- return $value;
62
- }
63
-
64
- protected function addUrlUniqueParams($value, $product, $codes)
65
- {
66
- $params = array();
67
- foreach ($codes as $attribut_code) {
68
- $data = $product->getData($attribut_code);
69
- if (empty($data)) {
70
- $this->skip = true;
71
- if ($this->getConfigVar('log_skip'))
72
- {
73
- $this->log(sprintf("product id %d product sku %s, can't fetch data from attribute: '%s' ('%s') to make create url.", $this->getProduct()->getId(), $this->getProduct()->getSku(), $attribut_code, $data));
74
- }
75
- return $value;
76
- }
77
- $params[$attribut_code] = $data;
78
- }
79
- $urlinfo = parse_url($value);
80
- if ($urlinfo !== false) {
81
- if (isset($urlinfo['query'])) {
82
- $urlinfo['query'] .= '&'.http_build_query($params);
83
- } else {
84
- $urlinfo['query'] = http_build_query($params);
85
- }
86
- $new = "";
87
- foreach ($urlinfo as $k => $v) {
88
- if ($k == 'scheme') {
89
- $new .= $v.'://';
90
- } elseif ($k == 'port') {
91
- $new .= ':'.$v;
92
- } elseif ($k == 'query') {
93
- $new .= '?'.$v;
94
- } else {
95
- $new .= $v;
96
- }
97
- }
98
- if (parse_url($new) === false) {
99
- $this->skip = true;
100
- if ($this->getConfigVar('log_skip'))
101
- {
102
- $this->log(sprintf("product id %d product sku %s, failed to from new url: %s from old url %s.", $this->getProduct()->getId(), $this->getProduct()->getSku(), $new, $value));
103
- }
104
- } else {
105
- $value = $new;
106
- }
107
- }
108
-
109
- return $value;
110
- }
111
-
112
- public function mapFieldImageLink($params = array())
113
- {
114
- $args = array('map' => $params['map']);
115
- $value = "";
116
-
117
- $value = $this->getCellValue($args);
118
- if ($value == '')
119
- {
120
- $value = $this->getParentMap()->mapField('image_link');
121
- }
122
-
123
- return $value;
124
- }
125
-
126
- /**
127
- * By default no additional images for associated products.
128
- *
129
- * @todo Comment this function to allow fetching additional images from the associated product.
130
- * @param array $params
131
- * @return string
132
- */
133
- public function mapFieldAdditionalImageLink($params = array())
134
- {
135
- $args = array('map' => $params['map']);
136
- $value = "";
137
-
138
- return $value;
139
- }
140
-
141
- public function mapFieldCurrentPrice($params = array())
142
- {
143
- $cell = "";
144
- if (!$this->getParentMap()->hasSpecialPrice())
145
- return $cell;
146
-
147
- $map = $params['map'];
148
- $product = $this->getProduct();
149
- /* @var $product Mage_Catalog_Model_Product */
150
-
151
- $helper = Mage::helper('feed/tax');
152
- /* @var $helper Mage_Tax_Helper_Data */
153
- /* 0 - excluding tax
154
- 1 - including tax */
155
- $priceIncludesTax = ( $helper->priceIncludesTax($this->getStoreId()) ? true : false);
156
- $includingTax = ($this->getConfigVar('add_tax_to_price', 'columns') ? true : false);
157
- $special_price = $this->getPrice() - $this->getParentMap()->getPrice() + $this->getParentMap()->getSpecialPrice();
158
- $price = $helper->getPrice($product, $special_price, $includingTax, false, false, null, $this->getStoreId(), $priceIncludesTax);
159
- $cell = $price;
160
-
161
- $cell = $this->cleanField($cell);
162
- return $cell;
163
- }
164
-
165
- public function mapFieldSalePriceEffectiveDate($params = array())
166
- {
167
- $args = array('map' => $params['map']);
168
- $value = "";
169
- $value = $this->getParentMap()->mapField('sale_price_effective_date');
170
- return $value;
171
- }
172
-
173
- public function mapFieldAvailability($params = array())
174
- {
175
- $args = array('map' => $params['map']);
176
- $value = "";
177
- $value = $this->getParentMap()->mapField('availability');
178
- // gets out of stock if parent is out of stock
179
- if (strcasecmp($this->getConfig()->getOutOfStockStatus(), $value) == 0)
180
- return $value;
181
-
182
- $value = $this->getCellValue($args);
183
-
184
- return $value;
185
- }
186
-
187
- public function mapFieldBrand($params = array())
188
- {
189
- $args = array('map' => $params['map']);
190
- $value = "";
191
-
192
- // get value from parent first
193
- $value = $this->getParentMap()->mapField('brand');
194
- if ($value != "")
195
- return $value;
196
-
197
- $value = $this->getCellValue($args);
198
-
199
- return $value;
200
- }
201
-
202
- public function mapFieldProductType($params = array())
203
- {
204
- $args = array('map' => $params['map']);
205
- $value = "";
206
-
207
- // get value from parent first
208
- $value = $this->getParentMap()->mapField('product_type');
209
- if ($value != "")
210
- return html_entity_decode($value);
211
-
212
- $map_by_category = $this->getConfig()->getMapCategorySorted('product_type_by_category', $this->getStoreId());
213
- $category_ids = $this->getProduct()->getCategoryIds();
214
- if (empty($category_ids))
215
- $category_ids = $this->getParentMap()->getProduct()->getCategoryIds();
216
- if (!empty($category_ids) && count($map_by_category) > 0)
217
- {
218
- foreach ($map_by_category as $arr)
219
- {
220
- if (array_search($arr['category'], $category_ids) !== false)
221
- {
222
- $value = $arr['value'];
223
- break;
224
- }
225
- }
226
- }
227
-
228
- if ($value != "")
229
- return html_entity_decode($value);
230
-
231
- $value = $this->getCellValue($args);
232
-
233
- return html_entity_decode($value);
234
- }
235
  }
1
+ <?php
2
+
3
+ /**
4
+ * NOTICE OF LICENSE
5
+ *
6
+ * This source file is subject to the Open Software License (OSL 3.0)
7
+ * that is bundled with this package in the file LICENSE.txt.
8
+ * It is also available through the world-wide-web at this URL:
9
+ * http://opensource.org/licenses/osl-3.0.php
10
+ *
11
+ * @category Sooqr
12
+ * @package Sooqr_Feed
13
+ * @copyright Copyright (c) 2011 RocketWeb (http://rocketweb.com)
14
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
15
+ * @author RocketWeb
16
+ */
17
+
18
+ class Sooqr_Feed_Model_Map_Product_Associated extends Sooqr_Feed_Model_Map_Product_Abstract
19
+ {
20
+ /**
21
+ * @param string $column
22
+ * @return string
23
+ */
24
+ protected function mapField($column)
25
+ {
26
+ $value = parent::mapField($column);
27
+ if ($value == "")
28
+ {
29
+ $value = $this->getParentMap()->mapField($column);
30
+ }
31
+
32
+ return $value;
33
+ }
34
+
35
+ public function mapFieldDescription($params = array())
36
+ {
37
+ $args = array('map' => $params['map']);
38
+ $value = "";
39
+
40
+ $value = $this->getCellValue($args);
41
+ if ($value == "")
42
+ $value = $this->getParentMap()->mapField('description');
43
+
44
+ return $value;
45
+ }
46
+
47
+ public function mapFieldLink($params = array())
48
+ {
49
+ $args = array('map' => $params['map']);
50
+ $product = $this->getProduct();
51
+ $value = "";
52
+
53
+ if ($product->isVisibleInSiteVisibility()) {
54
+ $value = $this->getCellValue($args);
55
+ } else {
56
+ $value = $this->getParentMap()->mapField('link');
57
+ if ($this->getConfigVar('associated_products_link_add_unique', 'columns'))
58
+ $value = $this->addUrlUniqueParams($value, $product, $this->getParentMap()->getConfigurableAttributeCodes());
59
+ }
60
+
61
+ return $value;
62
+ }
63
+
64
+ protected function addUrlUniqueParams($value, $product, $codes)
65
+ {
66
+ $params = array();
67
+ foreach ($codes as $attribut_code) {
68
+ $data = $product->getData($attribut_code);
69
+ if (empty($data)) {
70
+ $this->skip = true;
71
+ if ($this->getConfigVar('log_skip'))
72
+ {
73
+ $this->log(sprintf("product id %d product sku %s, can't fetch data from attribute: '%s' ('%s') to make create url.", $this->getProduct()->getId(), $this->getProduct()->getSku(), $attribut_code, $data));
74
+ }
75
+ return $value;
76
+ }
77
+ $params[$attribut_code] = $data;
78
+ }
79
+ $urlinfo = parse_url($value);
80
+ if ($urlinfo !== false) {
81
+ if (isset($urlinfo['query'])) {
82
+ $urlinfo['query'] .= '&'.http_build_query($params);
83
+ } else {
84
+ $urlinfo['query'] = http_build_query($params);
85
+ }
86
+ $new = "";
87
+ foreach ($urlinfo as $k => $v) {
88
+ if ($k == 'scheme') {
89
+ $new .= $v.'://';
90
+ } elseif ($k == 'port') {
91
+ $new .= ':'.$v;
92
+ } elseif ($k == 'query') {
93
+ $new .= '?'.$v;
94
+ } else {
95
+ $new .= $v;
96
+ }
97
+ }
98
+ if (parse_url($new) === false) {
99
+ $this->skip = true;
100
+ if ($this->getConfigVar('log_skip'))
101
+ {
102
+ $this->log(sprintf("product id %d product sku %s, failed to from new url: %s from old url %s.", $this->getProduct()->getId(), $this->getProduct()->getSku(), $new, $value));
103
+ }
104
+ } else {
105
+ $value = $new;
106
+ }
107
+ }
108
+
109
+ return $value;
110
+ }
111
+
112
+ public function mapFieldImageLink($params = array())
113
+ {
114
+ $args = array('map' => $params['map']);
115
+ $value = "";
116
+
117
+ $value = $this->getCellValue($args);
118
+ if ($value == '')
119
+ {
120
+ $value = $this->getParentMap()->mapField('image_link');
121
+ }
122
+
123
+ return $value;
124
+ }
125
+
126
+ /**
127
+ * By default no additional images for associated products.
128
+ *
129
+ * @todo Comment this function to allow fetching additional images from the associated product.
130
+ * @param array $params
131
+ * @return string
132
+ */
133
+ public function mapFieldAdditionalImageLink($params = array())
134
+ {
135
+ $args = array('map' => $params['map']);
136
+ $value = "";
137
+
138
+ return $value;
139
+ }
140
+
141
+ public function mapFieldCurrentPrice($params = array())
142
+ {
143
+ $cell = "";
144
+ if (!$this->getParentMap()->hasSpecialPrice())
145
+ return $cell;
146
+
147
+ $map = $params['map'];
148
+ $product = $this->getProduct();
149
+ /* @var $product Mage_Catalog_Model_Product */
150
+
151
+ $helper = Mage::helper('feed/tax');
152
+ /* @var $helper Mage_Tax_Helper_Data */
153
+ /* 0 - excluding tax
154
+ 1 - including tax */
155
+ $priceIncludesTax = ( $helper->priceIncludesTax($this->getStoreId()) ? true : false);
156
+ $includingTax = ($this->getConfigVar('add_tax_to_price', 'columns') ? true : false);
157
+ $special_price = $this->getPrice() - $this->getParentMap()->getPrice() + $this->getParentMap()->getSpecialPrice();
158
+ $price = $helper->getPrice($product, $special_price, $includingTax, false, false, null, $this->getStoreId(), $priceIncludesTax);
159
+ $cell = $price;
160
+
161
+ $cell = $this->cleanField($cell);
162
+ return $cell;
163
+ }
164
+
165
+ public function mapFieldSalePriceEffectiveDate($params = array())
166
+ {
167
+ $args = array('map' => $params['map']);
168
+ $value = "";
169
+ $value = $this->getParentMap()->mapField('sale_price_effective_date');
170
+ return $value;
171
+ }
172
+
173
+ public function mapFieldAvailability($params = array())
174
+ {
175
+ $args = array('map' => $params['map']);
176
+ $value = "";
177
+ $value = $this->getParentMap()->mapField('availability');
178
+ // gets out of stock if parent is out of stock
179
+ if (strcasecmp($this->getConfig()->getOutOfStockStatus(), $value) == 0)
180
+ return $value;
181
+
182
+ $value = $this->getCellValue($args);
183
+
184
+ return $value;
185
+ }
186
+
187
+ public function mapFieldBrand($params = array())
188
+ {
189
+ $args = array('map' => $params['map']);
190
+ $value = "";
191
+
192
+ // get value from parent first
193
+ $value = $this->getParentMap()->mapField('brand');
194
+ if ($value != "")
195
+ return $value;
196
+
197
+ $value = $this->getCellValue($args);
198
+
199
+ return $value;
200
+ }
201
+
202
+ public function mapFieldProductType($params = array())
203
+ {
204
+ $args = array('map' => $params['map']);
205
+ $value = "";
206
+
207
+ // get value from parent first
208
+ $value = $this->getParentMap()->mapField('product_type');
209
+ if ($value != "")
210
+ return html_entity_decode($value);
211
+
212
+ $map_by_category = $this->getConfig()->getMapCategorySorted('product_type_by_category', $this->getStoreId());
213
+ $category_ids = $this->getProduct()->getCategoryIds();
214
+ if (empty($category_ids))
215
+ $category_ids = $this->getParentMap()->getProduct()->getCategoryIds();
216
+ if (!empty($category_ids) && count($map_by_category) > 0)
217
+ {
218
+ foreach ($map_by_category as $arr)
219
+ {
220
+ if (array_search($arr['category'], $category_ids) !== false)
221
+ {
222
+ $value = $arr['value'];
223
+ break;
224
+ }
225
+ }
226
+ }
227
+
228
+ if ($value != "")
229
+ return html_entity_decode($value);
230
+
231
+ $value = $this->getCellValue($args);
232
+
233
+ return html_entity_decode($value);
234
+ }
235
  }
app/code/community/Sooqr/Feed/Model/Map/Product/Bundle.php CHANGED
@@ -19,53 +19,53 @@ class Sooqr_Feed_Model_Map_Product_Bundle extends Sooqr_Feed_Model_Map_Product_A
19
  {
20
  public function getPrice()
21
  {
22
- $price = 0.0;
23
- if (!$this->hasSpecialPrice())
24
- {
25
- //$price = $this->getProduct()->getMinimalPrice();
26
- $price = $this->calcMinimalPrice($this->getProduct());
27
- }
28
- else
29
- {
30
- //$price = $this->getProduct()->getMinimalPrice();
31
- $price = $this->calcMinimalPrice($this->getProduct());
32
- }
33
-
34
- if ($price <= 0) {
35
- $this->skip = true;
36
- if ($this->getConfigVar('log_skip'))
37
- {
38
- $this->log(sprintf("product id %d product sku %s, skipped - can't determine the minimal price: '%s'.", $this->getProduct()->getId(), $this->getProduct()->getSku(), $price));
39
- }
40
- }
41
-
42
- return $price;
43
  }
44
 
45
  public function calcMinimalPrice($product) {
46
- $price = 0.0;
47
- if ($this->getConfig()->compareMagentoVersion(array('major' => 1, 'minor' => 6, 'revision' => 0, 'patch' => 0))) {
48
- $_prices = $product->getPriceModel()->getTotalPrices($product);
49
- } else {
50
- $_prices = $product->getPriceModel()->getPrices($product);
51
- }
52
- if (is_array($_prices)) {
53
- $price = min($_prices);
54
- } else {
55
- $price = $_prices;
56
- }
57
 
58
- //return $product->getMinimalPrice();
59
- return $price;
60
  }
61
 
62
  public function getSpecialPrice()
63
  {
64
- $price = $this->calcMinimalPrice($this->getProduct());
65
- $special_price_percent = $this->getProduct()->getSpecialPrice();
66
- if ($special_price_percent <= 0 || $special_price_percent > 100)
67
- return 0;
68
- $special_price = (($special_price = (100 - $special_price_percent) * $price / 100) > 0 ? $special_price : 0);
69
- return $special_price;
70
  }
71
  }
19
  {
20
  public function getPrice()
21
  {
22
+ $price = 0.0;
23
+ if (!$this->hasSpecialPrice())
24
+ {
25
+ //$price = $this->getProduct()->getMinimalPrice();
26
+ $price = $this->calcMinimalPrice($this->getProduct());
27
+ }
28
+ else
29
+ {
30
+ //$price = $this->getProduct()->getMinimalPrice();
31
+ $price = $this->calcMinimalPrice($this->getProduct());
32
+ }
33
+
34
+ if ($price <= 0) {
35
+ $this->skip = true;
36
+ if ($this->getConfigVar('log_skip'))
37
+ {
38
+ $this->log(sprintf("product id %d product sku %s, skipped - can't determine the minimal price: '%s'.", $this->getProduct()->getId(), $this->getProduct()->getSku(), $price));
39
+ }
40
+ }
41
+
42
+ return $price;
43
  }
44
 
45
  public function calcMinimalPrice($product) {
46
+ $price = 0.0;
47
+ if ($this->getConfig()->compareMagentoVersion(array('major' => 1, 'minor' => 6, 'revision' => 0, 'patch' => 0))) {
48
+ $_prices = $product->getPriceModel()->getTotalPrices($product);
49
+ } else {
50
+ $_prices = $product->getPriceModel()->getPrices($product);
51
+ }
52
+ if (is_array($_prices)) {
53
+ $price = min($_prices);
54
+ } else {
55
+ $price = $_prices;
56
+ }
57
 
58
+ //return $product->getMinimalPrice();
59
+ return $price;
60
  }
61
 
62
  public function getSpecialPrice()
63
  {
64
+ $price = $this->calcMinimalPrice($this->getProduct());
65
+ $special_price_percent = $this->getProduct()->getSpecialPrice();
66
+ if ($special_price_percent <= 0 || $special_price_percent > 100)
67
+ return 0;
68
+ $special_price = (($special_price = (100 - $special_price_percent) * $price / 100) > 0 ? $special_price : 0);
69
+ return $special_price;
70
  }
71
  }
app/code/community/Sooqr/Feed/Model/Map/Product/Configurable.php CHANGED
@@ -1,295 +1,295 @@
1
- <?php
2
-
3
- /**
4
- * NOTICE OF LICENSE
5
- *
6
- * This source file is subject to the Open Software License (OSL 3.0)
7
- * that is bundled with this package in the file LICENSE.txt.
8
- * It is also available through the world-wide-web at this URL:
9
- * http://opensource.org/licenses/osl-3.0.php
10
- *
11
- * @category Sooqr
12
- * @package Sooqr_Feed
13
- * @copyright Copyright (c) 2011 RocketWeb (http://rocketweb.com)
14
- * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
15
- * @author RocketWeb
16
- */
17
-
18
- class Sooqr_Feed_Model_Map_Product_Configurable extends Sooqr_Feed_Model_Map_Product_Abstract
19
- {
20
- protected $_assoc_ids;
21
- protected $_assocs;
22
- protected $_cache_configurable_attribute_codes;
23
-
24
- public function _beforeMap()
25
- {
26
- $this->_assocs = array();
27
-
28
- // Create a product model for each associated product
29
- foreach ($this->getAssocIds() as $assocId)
30
- {
31
- $assoc = Mage::getModel('catalog/product');
32
- $assoc->setStoreId($this->getStoreId());
33
- $assoc->getResource()->load($assoc, $assocId);
34
- $this->_assocs[$assocId] = $assoc;
35
- }
36
-
37
- $assocMapArr = array();
38
- foreach ($this->_assocs as $assoc)
39
- {
40
- $assocMap = $this->getAssocMapModel($assoc);
41
- if ($assocMap->checkSkipSubmission()->isSkip())
42
- {
43
- continue;
44
- }
45
- $assocMapArr[$assoc->getId()] = $assocMap;
46
- }
47
-
48
- $this->setAssocMaps($assocMapArr);
49
-
50
- return parent::_beforeMap();
51
- }
52
-
53
- public function _map()
54
- {
55
- $rows = array();
56
-
57
- // Check if this product should be in the feed
58
- if (!$this->isSkip())
59
- {
60
- $masterData = parent::_map();
61
- reset($masterData);
62
- $masterData = current($masterData);
63
-
64
- // Only add the master data is we don't group products
65
- if ($this->getConfigVar('group_configurable_products') == 0)
66
- {
67
- $rows[] = $masterData;
68
- }
69
- }
70
-
71
- // Map all child products
72
- foreach ($this->getAssocMaps() as $assocId => $assocMap)
73
- {
74
- if (!$assocMap->isSkip())
75
- {
76
  $row = $assocMap->map();
77
  reset($row);
78
  $row = current($row);
79
-
80
- // We can group multiple configurable products into the master product
81
- if ($this->getConfigVar('group_configurable_products') == 1)
82
- {
83
- foreach ($row as $name => $value)
84
- {
85
- // id value is always unique
86
- if ($name == 'id')
87
- {
88
- continue;
89
- }
90
- else if ($name == 'price'
91
- || $name == 'normal_price')
92
- {
93
- if ($this->getConfigVar('price_in_configurable_group') == 'min'
94
- && $value < $masterData[$name])
95
- {
96
- $masterData[$name] = $value;
97
- }
98
- else if ($this->getConfigVar('price_in_configurable_group') == 'max'
99
- && $value > $masterData[$name])
100
- {
101
- $masterData[$name] = $value;
102
- }
103
- continue;
104
- }
105
-
106
- if (!is_array($masterData[$name]))
107
- {
108
- if ($masterData[$name] != $value)
109
- {
110
- if (strlen($masterData[$name]))
111
- {
112
- $masterData[$name] = array($masterData[$name], $value);
113
- }
114
- else
115
- {
116
- $masterData[$name] = $value;
117
- }
118
- }
119
- }
120
- else
121
- {
122
- if (!in_array($value, $masterData[$name]))
123
- {
124
- $masterData[$name][] = $value;
125
- }
126
- }
127
- }
128
- }
129
- else
130
- {
131
- // Add each configurable product as separate product
132
- $rows[] = $row;
133
- }
134
- }
135
- }
136
-
137
  // Add the complete master data object
138
  if ($this->getConfigVar('group_configurable_products') == 1)
139
- {
140
  $rows[] = $masterData;
141
- }
142
-
143
- return $rows;
144
- }
145
-
146
- /**
147
- * Array with associated products ids in current store.
148
- *
149
- * @return array
150
- */
151
- public function getAssocIds()
152
- {
153
- if (is_null($this->_assoc_ids))
154
- {
155
- $this->_assoc_ids = $this->loadAssocIds($this->getProduct(), $this->getStoreId());
156
- }
157
- return $this->_assoc_ids;
158
- }
159
-
160
- /**
161
- * @param Mage_Catalog_Model_Product $product
162
- * @return Sooqr_Feed_Model_Map_Product_Abstract
163
- */
164
- protected function getAssocMapModel($oProduct)
165
- {
166
- $params = array(
167
- 'store_code' => $this->getData('store_code'),
168
- 'store_id' => $this->getData('store_id'),
169
- 'website_id' => $this->getData('website_id'),
170
- );
171
-
172
- $productMap = Mage::getModel('feed/map_product_associated', $params);
173
-
174
- $productMap->setGenerator($this->getGenerator())
175
- ->setProduct($oProduct)
176
- ->setFieldsMap($this->_field_map)
177
- ->setParentMap($this)
178
- ->initialize();
179
-
180
- return $productMap;
181
- }
182
-
183
- /**
184
- * @param array $params
185
- * @return string
186
- */
187
- protected function mapAttributeWeight($params = array())
188
- {
189
- $map = $params['map'];
190
- $product = $this->getProduct();
191
- /* @var $product Mage_Catalog_Model_Product */
192
- $cell = "";
193
-
194
- $default_value = isset($map['default_value']) ? $map['default_value'] : "";
195
- if ($default_value != "")
196
- {
197
- $weight = $default_value;
198
- $weight .= ' '.$this->getConfigVar('weight_unit_measure', 'columns');
199
-
200
- $cell = $weight;
201
- $cell = $this->cleanField($cell);
202
- return $cell;
203
- }
204
-
205
- $weight_attribute = $this->getGenerator()->getAttribute($map['attribute']);
206
- if ($weight_attribute === false)
207
- Mage::throwException(sprintf('Couldn\'t find attribute \'%s\'.', $map['attribute']));
208
-
209
- $weight = $this->getAttributeValue($product, $weight_attribute);
210
- if ($weight != "")
211
- $weight .= ' '.$this->getConfigVar('weight_unit_measure', 'columns');
212
-
213
- // Configurable doesn't have weight of it's own.
214
- if ($weight == "")
215
- {
216
- $min_price = PHP_INT_MAX;
217
- foreach ($this->_assocs as $assoc)
218
- {
219
- if ($min_price > $assoc->getFinalPrice())
220
- {
221
- $min_price = $assoc->getFinalPrice();
222
- $weight = $this->getAttributeValue($assoc, $weight_attribute);
223
- break;
224
- }
225
- }
226
- }
227
-
228
- if ($weight != "")
229
- $weight .= ' '.$this->getConfigVar('weight_unit_measure', 'columns');
230
-
231
- $cell = $weight;
232
-
233
- $cell = $this->cleanField($cell);
234
- return $cell;
235
- }
236
-
237
- public function getPrice()
238
- {
239
- $price = 0.0;
240
- if (!$this->hasSpecialPrice())
241
- {
242
- $price = $this->calcMinimalPrice($this->getProduct());
243
- }
244
- else
245
- {
246
- $price = $this->getProduct()->getPrice();
247
- }
248
-
249
- if ($price <= 0) {
250
- $this->skip = true;
251
- if ($this->getConfigVar('log_skip'))
252
- {
253
- $this->log(sprintf("product id %d product sku %s, skipped - can't determine the minimal price: '%s'.", $this->getProduct()->getId(), $this->getProduct()->getSku(), $price));
254
- }
255
- }
256
-
257
- return $price;
258
- }
259
-
260
- /**
261
- * @return float
262
- */
263
- public function calcMinimalPrice($product)
264
- {
265
- $price = 0.0;
266
- $minimal_price = PHP_INT_MAX;
267
- foreach ($this->_assocs as $assoc)
268
- {
269
- if ($minimal_price > $assoc->getPrice())
270
- {
271
- $minimal_price = $assoc->getPrice();
272
- }
273
- }
274
- if ($minimal_price < PHP_INT_MAX)
275
- {
276
- $price = $minimal_price;
277
- }
278
-
279
- return $price;
280
- }
281
-
282
- /**
283
- * @return array()
284
- */
285
- public function getConfigurableAttributeCodes()
286
- {
287
- if (is_null($this->_cache_configurable_attribute_codes))
288
- {
289
- $this->_cache_configurable_attribute_codes = $this->getTools()
290
- ->getConfigurableAttributeCodes($this->getProduct()->getId());
291
- }
292
-
293
- return $this->_cache_configurable_attribute_codes;
294
- }
295
  }
1
+ <?php
2
+
3
+ /**
4
+ * NOTICE OF LICENSE
5
+ *
6
+ * This source file is subject to the Open Software License (OSL 3.0)
7
+ * that is bundled with this package in the file LICENSE.txt.
8
+ * It is also available through the world-wide-web at this URL:
9
+ * http://opensource.org/licenses/osl-3.0.php
10
+ *
11
+ * @category Sooqr
12
+ * @package Sooqr_Feed
13
+ * @copyright Copyright (c) 2011 RocketWeb (http://rocketweb.com)
14
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
15
+ * @author RocketWeb
16
+ */
17
+
18
+ class Sooqr_Feed_Model_Map_Product_Configurable extends Sooqr_Feed_Model_Map_Product_Abstract
19
+ {
20
+ protected $_assoc_ids;
21
+ protected $_assocs;
22
+ protected $_cache_configurable_attribute_codes;
23
+
24
+ public function _beforeMap()
25
+ {
26
+ $this->_assocs = array();
27
+
28
+ // Create a product model for each associated product
29
+ foreach ($this->getAssocIds() as $assocId)
30
+ {
31
+ $assoc = Mage::getModel('catalog/product');
32
+ $assoc->setStoreId($this->getStoreId());
33
+ $assoc->getResource()->load($assoc, $assocId);
34
+ $this->_assocs[$assocId] = $assoc;
35
+ }
36
+
37
+ $assocMapArr = array();
38
+ foreach ($this->_assocs as $assoc)
39
+ {
40
+ $assocMap = $this->getAssocMapModel($assoc);
41
+ if ($assocMap->checkSkipSubmission()->isSkip())
42
+ {
43
+ continue;
44
+ }
45
+ $assocMapArr[$assoc->getId()] = $assocMap;
46
+ }
47
+
48
+ $this->setAssocMaps($assocMapArr);
49
+
50
+ return parent::_beforeMap();
51
+ }
52
+
53
+ public function _map()
54
+ {
55
+ $rows = array();
56
+
57
+ // Check if this product should be in the feed
58
+ if (!$this->isSkip())
59
+ {
60
+ $masterData = parent::_map();
61
+ reset($masterData);
62
+ $masterData = current($masterData);
63
+
64
+ // Only add the master data is we don't group products
65
+ if ($this->getConfigVar('group_configurable_products') == 0)
66
+ {
67
+ $rows[] = $masterData;
68
+ }
69
+ }
70
+
71
+ // Map all child products
72
+ foreach ($this->getAssocMaps() as $assocId => $assocMap)
73
+ {
74
+ if (!$assocMap->isSkip())
75
+ {
76
  $row = $assocMap->map();
77
  reset($row);
78
  $row = current($row);
79
+
80
+ // We can group multiple configurable products into the master product
81
+ if ($this->getConfigVar('group_configurable_products') == 1)
82
+ {
83
+ foreach ($row as $name => $value)
84
+ {
85
+ // id value is always unique
86
+ if ($name == 'id')
87
+ {
88
+ continue;
89
+ }
90
+ else if ($name == 'price'
91
+ || $name == 'normal_price')
92
+ {
93
+ if ($this->getConfigVar('price_in_configurable_group') == 'min'
94
+ && $value < $masterData[$name])
95
+ {
96
+ $masterData[$name] = $value;
97
+ }
98
+ else if ($this->getConfigVar('price_in_configurable_group') == 'max'
99
+ && $value > $masterData[$name])
100
+ {
101
+ $masterData[$name] = $value;
102
+ }
103
+ continue;
104
+ }
105
+
106
+ if (!is_array($masterData[$name]))
107
+ {
108
+ if ($masterData[$name] != $value)
109
+ {
110
+ if (strlen($masterData[$name]))
111
+ {
112
+ $masterData[$name] = array($masterData[$name], $value);
113
+ }
114
+ else
115
+ {
116
+ $masterData[$name] = $value;
117
+ }
118
+ }
119
+ }
120
+ else
121
+ {
122
+ if (!in_array($value, $masterData[$name]))
123
+ {
124
+ $masterData[$name][] = $value;
125
+ }
126
+ }
127
+ }
128
+ }
129
+ else
130
+ {
131
+ // Add each configurable product as separate product
132
+ $rows[] = $row;
133
+ }
134
+ }
135
+ }
136
+
137
  // Add the complete master data object
138
  if ($this->getConfigVar('group_configurable_products') == 1)
139
+ {
140
  $rows[] = $masterData;
141
+ }
142
+
143
+ return $rows;
144
+ }
145
+
146
+ /**
147
+ * Array with associated products ids in current store.
148
+ *
149
+ * @return array
150
+ */
151
+ public function getAssocIds()
152
+ {
153
+ if (is_null($this->_assoc_ids))
154
+ {
155
+ $this->_assoc_ids = $this->loadAssocIds($this->getProduct(), $this->getStoreId());
156
+ }
157
+ return $this->_assoc_ids;
158
+ }
159
+
160
+ /**
161
+ * @param Mage_Catalog_Model_Product $product
162
+ * @return Sooqr_Feed_Model_Map_Product_Abstract
163
+ */
164
+ protected function getAssocMapModel($oProduct)
165
+ {
166
+ $params = array(
167
+ 'store_code' => $this->getData('store_code'),
168
+ 'store_id' => $this->getData('store_id'),
169
+ 'website_id' => $this->getData('website_id'),
170
+ );
171
+
172
+ $productMap = Mage::getModel('feed/map_product_associated', $params);
173
+
174
+ $productMap->setGenerator($this->getGenerator())
175
+ ->setProduct($oProduct)
176
+ ->setFieldsMap($this->_field_map)
177
+ ->setParentMap($this)
178
+ ->initialize();
179
+
180
+ return $productMap;
181
+ }
182
+
183
+ /**
184
+ * @param array $params
185
+ * @return string
186
+ */
187
+ protected function mapAttributeWeight($params = array())
188
+ {
189
+ $map = $params['map'];
190
+ $product = $this->getProduct();
191
+ /* @var $product Mage_Catalog_Model_Product */
192
+ $cell = "";
193
+
194
+ $default_value = isset($map['default_value']) ? $map['default_value'] : "";
195
+ if ($default_value != "")
196
+ {
197
+ $weight = $default_value;
198
+ $weight .= ' '.$this->getConfigVar('weight_unit_measure', 'columns');
199
+
200
+ $cell = $weight;
201
+ $cell = $this->cleanField($cell);
202
+ return $cell;
203
+ }
204
+
205
+ $weight_attribute = $this->getGenerator()->getAttribute($map['attribute']);
206
+ if ($weight_attribute === false)
207
+ Mage::throwException(sprintf('Couldn\'t find attribute \'%s\'.', $map['attribute']));
208
+
209
+ $weight = $this->getAttributeValue($product, $weight_attribute);
210
+ if ($weight != "")
211
+ $weight .= ' '.$this->getConfigVar('weight_unit_measure', 'columns');
212
+
213
+ // Configurable doesn't have weight of it's own.
214
+ if ($weight == "")
215
+ {
216
+ $min_price = PHP_INT_MAX;
217
+ foreach ($this->_assocs as $assoc)
218
+ {
219
+ if ($min_price > $assoc->getFinalPrice())
220
+ {
221
+ $min_price = $assoc->getFinalPrice();
222
+ $weight = $this->getAttributeValue($assoc, $weight_attribute);
223
+ break;
224
+ }
225
+ }
226
+ }
227
+
228
+ if ($weight != "")
229
+ $weight .= ' '.$this->getConfigVar('weight_unit_measure', 'columns');
230
+
231
+ $cell = $weight;
232
+
233
+ $cell = $this->cleanField($cell);
234
+ return $cell;
235
+ }
236
+
237
+ public function getPrice()
238
+ {
239
+ $price = 0.0;
240
+ if (!$this->hasSpecialPrice())
241
+ {
242
+ $price = $this->calcMinimalPrice($this->getProduct());
243
+ }
244
+ else
245
+ {
246
+ $price = $this->getProduct()->getPrice();
247
+ }
248
+
249
+ if ($price <= 0) {
250
+ $this->skip = true;
251
+ if ($this->getConfigVar('log_skip'))
252
+ {
253
+ $this->log(sprintf("product id %d product sku %s, skipped - can't determine the minimal price: '%s'.", $this->getProduct()->getId(), $this->getProduct()->getSku(), $price));
254
+ }
255
+ }
256
+
257
+ return $price;
258
+ }
259
+
260
+ /**
261
+ * @return float
262
+ */
263
+ public function calcMinimalPrice($product)
264
+ {
265
+ $price = 0.0;
266
+ $minimal_price = PHP_INT_MAX;
267
+ foreach ($this->_assocs as $assoc)
268
+ {
269
+ if ($minimal_price > $assoc->getPrice())
270
+ {
271
+ $minimal_price = $assoc->getPrice();
272
+ }
273
+ }
274
+ if ($minimal_price < PHP_INT_MAX)
275
+ {
276
+ $price = $minimal_price;
277
+ }
278
+
279
+ return $price;
280
+ }
281
+
282
+ /**
283
+ * @return array()
284
+ */
285
+ public function getConfigurableAttributeCodes()
286
+ {
287
+ if (is_null($this->_cache_configurable_attribute_codes))
288
+ {
289
+ $this->_cache_configurable_attribute_codes = $this->getTools()
290
+ ->getConfigurableAttributeCodes($this->getProduct()->getId());
291
+ }
292
+
293
+ return $this->_cache_configurable_attribute_codes;
294
+ }
295
  }
app/code/community/Sooqr/Feed/Model/Map/Product/Grouped.php CHANGED
@@ -1,66 +1,71 @@
1
- <?php
2
-
3
- /**
4
- * NOTICE OF LICENSE
5
- *
6
- * This source file is subject to the Open Software License (OSL 3.0)
7
- * that is bundled with this package in the file LICENSE.txt.
8
- * It is also available through the world-wide-web at this URL:
9
- * http://opensource.org/licenses/osl-3.0.php
10
- *
11
- * @category Sooqr
12
- * @package Sooqr_Feed
13
- * @copyright Copyright (c) 2011 RocketWeb (http://rocketweb.com)
14
- * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
15
- * @author RocketWeb
16
- */
17
-
18
- class Sooqr_Feed_Model_Map_Product_Grouped extends Sooqr_Feed_Model_Map_Product_Abstract
19
- {
20
- /**
21
- * Grouped products doesn't have special price.
22
- *
23
- * @return float
24
- */
25
- public function getPrice()
26
- {
27
- $price = $this->calcGroupPrice($this->getProduct());
28
- if ($price <= 0)
29
- {
30
- $this->skip = true;
31
- if ($this->getConfigVar('log_skip'))
32
- {
33
- $this->log(sprintf("product id %d product sku %s, skipped - can't determine the minimal price: '%s'.", $this->getProduct()->getId(), $this->getProduct()->getSku(), $price));
34
- }
35
- }
36
-
37
- return $price;
38
- }
39
-
40
- public function calcGroupPrice($product)
41
- {
42
- $price = 0.0;
43
-
44
- foreach ($product->getTypeInstance()->getAssociatedProducts() as $associatedProduct)
45
- {
46
- if ($price == 0)
47
- {
48
- $price = $associatedProduct->getPrice();
49
- }
50
- else if ($this->getConfigVar('price_in_grouped_group') == 'min')
51
- {
52
- $price = min($price, $associatedProduct->getPrice());
53
- }
54
- else if ($this->getConfigVar('price_in_grouped_group') == 'max')
55
- {
56
- $price = max($price, $associatedProduct->getPrice());
57
- }
58
- else
59
- {
60
- $price += $associatedProduct->getPrice();
61
- }
62
- }
63
-
64
- return $price;
65
- }
 
 
 
 
 
66
  }
1
+ <?php
2
+
3
+ /**
4
+ * NOTICE OF LICENSE
5
+ *
6
+ * This source file is subject to the Open Software License (OSL 3.0)
7
+ * that is bundled with this package in the file LICENSE.txt.
8
+ * It is also available through the world-wide-web at this URL:
9
+ * http://opensource.org/licenses/osl-3.0.php
10
+ *
11
+ * @category Sooqr
12
+ * @package Sooqr_Feed
13
+ * @copyright Copyright (c) 2011 RocketWeb (http://rocketweb.com)
14
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
15
+ * @author RocketWeb
16
+ */
17
+
18
+ class Sooqr_Feed_Model_Map_Product_Grouped extends Sooqr_Feed_Model_Map_Product_Abstract
19
+ {
20
+ /**
21
+ * Grouped products doesn't have special price.
22
+ *
23
+ * @return float
24
+ */
25
+ public function getPrice()
26
+ {
27
+ $price = $this->calcGroupPrice($this->getProduct());
28
+ if ($price <= 0)
29
+ {
30
+ $this->skip = true;
31
+ if ($this->getConfigVar('log_skip'))
32
+ {
33
+ $this->log(sprintf("product id %d product sku %s, skipped - can't determine the minimal price: '%s'.", $this->getProduct()->getId(), $this->getProduct()->getSku(), $price));
34
+ }
35
+ }
36
+
37
+ return $price;
38
+ }
39
+
40
+ public function getFinalPrice()
41
+ {
42
+ return $this->getPrice();
43
+ }
44
+
45
+ public function calcGroupPrice($product)
46
+ {
47
+ $price = 0.0;
48
+
49
+ foreach ($product->getTypeInstance()->getAssociatedProducts() as $associatedProduct)
50
+ {
51
+ if ($price == 0)
52
+ {
53
+ $price = $associatedProduct->getPrice();
54
+ }
55
+ else if ($this->getConfigVar('price_in_grouped_group') == 'min')
56
+ {
57
+ $price = min($price, $associatedProduct->getPrice());
58
+ }
59
+ else if ($this->getConfigVar('price_in_grouped_group') == 'max')
60
+ {
61
+ $price = max($price, $associatedProduct->getPrice());
62
+ }
63
+ else
64
+ {
65
+ $price += $associatedProduct->getPrice();
66
+ }
67
+ }
68
+
69
+ return $price;
70
+ }
71
  }
app/code/community/Sooqr/Feed/Model/Source/Producttypes.php CHANGED
@@ -20,12 +20,12 @@ class Sooqr_Feed_Model_Source_Producttypes extends Varien_Object
20
  public function toOptionArray()
21
  {
22
  $values = array(
23
- Mage_Catalog_Model_Product_Type::TYPE_BUNDLE => ucwords(Mage_Catalog_Model_Product_Type::TYPE_BUNDLE),
24
- Mage_Catalog_Model_Product_Type::TYPE_CONFIGURABLE => ucwords(Mage_Catalog_Model_Product_Type::TYPE_CONFIGURABLE),
25
- Mage_Downloadable_Model_Product_Type::TYPE_DOWNLOADABLE => ucwords(Mage_Downloadable_Model_Product_Type::TYPE_DOWNLOADABLE),
26
- Mage_Catalog_Model_Product_Type::TYPE_GROUPED => ucwords(Mage_Catalog_Model_Product_Type::TYPE_GROUPED),
27
- Mage_Catalog_Model_Product_Type::TYPE_SIMPLE => ucwords(Mage_Catalog_Model_Product_Type::TYPE_SIMPLE),
28
- Mage_Catalog_Model_Product_Type::TYPE_VIRTUAL => ucwords(Mage_Catalog_Model_Product_Type::TYPE_VIRTUAL),
29
  );
30
 
31
  $options = array();
20
  public function toOptionArray()
21
  {
22
  $values = array(
23
+ Mage_Catalog_Model_Product_Type::TYPE_BUNDLE => ucwords(Mage_Catalog_Model_Product_Type::TYPE_BUNDLE),
24
+ Mage_Catalog_Model_Product_Type::TYPE_CONFIGURABLE => ucwords(Mage_Catalog_Model_Product_Type::TYPE_CONFIGURABLE),
25
+ Mage_Downloadable_Model_Product_Type::TYPE_DOWNLOADABLE => ucwords(Mage_Downloadable_Model_Product_Type::TYPE_DOWNLOADABLE),
26
+ Mage_Catalog_Model_Product_Type::TYPE_GROUPED => ucwords(Mage_Catalog_Model_Product_Type::TYPE_GROUPED),
27
+ Mage_Catalog_Model_Product_Type::TYPE_SIMPLE => ucwords(Mage_Catalog_Model_Product_Type::TYPE_SIMPLE),
28
+ Mage_Catalog_Model_Product_Type::TYPE_VIRTUAL => ucwords(Mage_Catalog_Model_Product_Type::TYPE_VIRTUAL),
29
  );
30
 
31
  $options = array();
app/code/community/Sooqr/Feed/Model/System/Config/Backend/Serialized/Customfieldmap.php CHANGED
@@ -27,18 +27,19 @@
27
 
28
  class Sooqr_Feed_Model_System_Config_Backend_Serialized_Customfieldmap extends Mage_Adminhtml_Model_System_Config_Backend_Serialized_Array
29
  {
30
- protected function _beforeSave()
31
  {
32
  $value = $this->_sqrCleanValue($this->getValue());
33
  $this->setValue($value);
34
  parent::_beforeSave();
35
  }
36
 
37
- protected function _afterLoad()
38
- {
39
- parent::_afterLoad();
40
-
41
  $values = $this->getValue();
 
42
  foreach ($values as &$value)
43
  {
44
  $value['field'] = 'sqr_'.$value['attribute'];
@@ -49,19 +50,19 @@ class Sooqr_Feed_Model_System_Config_Backend_Serialized_Customfieldmap extends M
49
 
50
  protected function _sqrCleanValue($value)
51
  {
52
- if (is_array($value))
53
- {
54
- foreach ($value as $k => $v)
55
- {
56
- if (is_array($v)
57
- && isset($v['field']))
58
- {
59
- $value[$k]['field'] = str_replace(" ", "_", trim(strtolower($v['field'])));
60
- $value[$k]['field'] = preg_replace('/__*/', '_', $value[$k]['field']);
61
- $value[$k]['field'] = trim($value[$k]['field'], "_");
62
- }
63
- }
64
- }
65
- return $value;
66
  }
67
  }
27
 
28
  class Sooqr_Feed_Model_System_Config_Backend_Serialized_Customfieldmap extends Mage_Adminhtml_Model_System_Config_Backend_Serialized_Array
29
  {
30
+ protected function _beforeSave()
31
  {
32
  $value = $this->_sqrCleanValue($this->getValue());
33
  $this->setValue($value);
34
  parent::_beforeSave();
35
  }
36
 
37
+ protected function _afterLoad()
38
+ {
39
+ parent::_afterLoad();
40
+
41
  $values = $this->getValue();
42
+ $values = is_array($values) ? $values : array();
43
  foreach ($values as &$value)
44
  {
45
  $value['field'] = 'sqr_'.$value['attribute'];
50
 
51
  protected function _sqrCleanValue($value)
52
  {
53
+ if (is_array($value))
54
+ {
55
+ foreach ($value as $k => $v)
56
+ {
57
+ if (is_array($v)
58
+ && isset($v['field']))
59
+ {
60
+ $value[$k]['field'] = str_replace(" ", "_", trim(strtolower($v['field'])));
61
+ $value[$k]['field'] = preg_replace('/__*/', '_', $value[$k]['field']);
62
+ $value[$k]['field'] = trim($value[$k]['field'], "_");
63
+ }
64
+ }
65
+ }
66
+ return $value;
67
  }
68
  }
app/code/community/Sooqr/Feed/Model/System/Config/Backend/Serialized/Fieldmap.php CHANGED
@@ -27,7 +27,7 @@
27
 
28
  class Sooqr_Feed_Model_System_Config_Backend_Serialized_Fieldmap extends Mage_Adminhtml_Model_System_Config_Backend_Serialized_Array
29
  {
30
- protected function _beforeSave()
31
  {
32
  $value = $this->_sqrCleanValue($this->getValue());
33
  $this->setValue($value);
@@ -67,19 +67,19 @@ class Sooqr_Feed_Model_System_Config_Backend_Serialized_Fieldmap extends Mage_Ad
67
 
68
  protected function _sqrCleanValue($value)
69
  {
70
- if (is_array($value))
71
- {
72
- foreach ($value as $k => $v)
73
- {
74
- if (is_array($v)
75
- && isset($v['field']))
76
- {
77
- $value[$k]['field'] = str_replace(" ", "_", trim(strtolower($v['field'])));
78
- $value[$k]['field'] = preg_replace('/__*/', '_', $value[$k]['field']);
79
- $value[$k]['field'] = trim($value[$k]['field'], "_");
80
- }
81
- }
82
- }
83
- return $value;
84
  }
85
  }
27
 
28
  class Sooqr_Feed_Model_System_Config_Backend_Serialized_Fieldmap extends Mage_Adminhtml_Model_System_Config_Backend_Serialized_Array
29
  {
30
+ protected function _beforeSave()
31
  {
32
  $value = $this->_sqrCleanValue($this->getValue());
33
  $this->setValue($value);
67
 
68
  protected function _sqrCleanValue($value)
69
  {
70
+ if (is_array($value))
71
+ {
72
+ foreach ($value as $k => $v)
73
+ {
74
+ if (is_array($v)
75
+ && isset($v['field']))
76
+ {
77
+ $value[$k]['field'] = str_replace(" ", "_", trim(strtolower($v['field'])));
78
+ $value[$k]['field'] = preg_replace('/__*/', '_', $value[$k]['field']);
79
+ $value[$k]['field'] = trim($value[$k]['field'], "_");
80
+ }
81
+ }
82
+ }
83
+ return $value;
84
  }
85
  }
app/code/community/Sooqr/Feed/Model/Tools.php CHANGED
@@ -25,78 +25,334 @@
25
 
26
  class Sooqr_Feed_Model_Tools extends Varien_Object
27
  {
28
- public function _construct()
29
- {
30
- parent::_construct();
31
- $this->loadEntityType('catalog_product');
32
- }
33
-
34
- public function loadEntityType($type)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  {
36
- if (is_array($type))
37
- {
38
- foreach ($type as $t)
39
- if (is_string($t))
40
- $this->loadEntityType($t);
41
- }
42
- else
43
- {
44
- $entityType = Mage::getModel('eav/config')->getEntityType('catalog_product');
45
-
46
- Mage::register('feed/entity_type/'.$type, $entityType);
47
- }
48
  return $this;
49
  }
50
 
51
  public function getEntityType($type)
52
  {
53
- return Mage::registry('feed/entity_type/'.$type);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  }
55
-
56
- public function getProductAttributeValueBySql($attribute, $type = "text", $productId, $storeId = null, $strict = false, $debug = false)
57
- {
58
- if (array_search($type, array('text', 'int', 'decimal', 'varchar', 'datetime')) === false)
59
- {
60
- Mage::throwException(sprintf("Unknown attribute backend type %s for attribute code %s.", $type, $attribute->getAttributeCode()));
61
- }
62
-
63
- if (is_null($storeId))
64
- {
65
- return $this->getProductAttributeValueBySql($attribute, $type, $productId, Mage_Core_Model_App::ADMIN_STORE_ID, true, $debug);
66
- }
67
-
68
- $attributeId = $attribute->getAttributeId();
69
-
70
- $sql = "SELECT val.value
71
- FROM ".$this->getRes()->getTableName('catalog/product')."_".$type." val
72
- INNER JOIN ".$this->getRes()->getTableName('eav/attribute')." eav ON val.attribute_id=eav.attribute_id
73
- WHERE
74
- val.entity_id='".addslashes($productId)."'
75
- AND
76
- val.entity_type_id = ".$this->getEntityType('catalog_product')->getEntityTypeId()."
77
- AND
78
- val.store_id = '".addslashes($storeId)."'
79
- AND
80
- val.attribute_id = '".addslashes($attributeId)."'";
81
- if ($debug)
82
- var_dump($sql);
83
- $value = $this->getConnRead()->fetchCol($sql);
84
- if (is_array($value) && @$value[0] === null)
85
- $value = null;
86
- elseif (is_array($value) && isset($value[0]))
87
- $value = $value[0];
88
- else if (is_array($value) && count($value) == 0)
89
- $value = null;
90
-
91
- if (is_null($value) && $storeId != Mage_Core_Model_App::ADMIN_STORE_ID && $strict === false)
92
- {
93
- return $this->getProductAttributeValueBySql($attribute, $type, $productId, Mage_Core_Model_App::ADMIN_STORE_ID, true, $debug);
94
- }
95
-
96
- return $value;
97
- }
98
-
99
- /**
100
  * Check if there is a parent of type (configurable, ..)
101
  *
102
  * @param string $type_id
@@ -106,74 +362,74 @@ class Sooqr_Feed_Model_Tools extends Varien_Object
106
  */
107
  public function isChildOfProductType($type_id, $sku, $parent_type_id)
108
  {
109
- $data = false;
110
-
111
- if ($type_id != Mage_Catalog_Model_Product_Type::TYPE_SIMPLE)
112
- return $data;
113
-
114
- $sql = "SELECT
115
- `cpe`.`entity_id` AS 'entity_id',
116
- `cpe`.`sku` AS 'sku',
117
- `cpe_parent`.`entity_id` AS 'parent_entity_id',
118
- `cpe_parent`.`sku` AS 'parent_sku'
119
- FROM `".$this->getRes()->getTableName('catalog/product')."` AS `cpe`
120
- INNER JOIN `".$this->getRes()->getTableName('catalog/product_super_link')."` AS `cpsl`
121
- ON `cpe`.`entity_id`=`cpsl`.`product_id`
122
- INNER JOIN `".$this->getRes()->getTableName('catalog/product')."` AS `cpe_parent`
123
- ON `cpsl`.`parent_id`=`cpe_parent`.`entity_id`
124
- WHERE
125
- `cpe`.`sku`=\"".addslashes($sku)."\"
126
- AND
127
- `cpe_parent`.`type_id`=\"".addslashes($parent_type_id)."\"";
128
- $result = $this->getConnRead()->fetchRow($sql);
129
-
130
- if ($result !== false)
131
- {
132
- $data = $result;
133
- }
134
-
135
- return $data;
136
  }
137
 
138
  public function getProductAttributeSelectValue($attribute, $valueId, $storeId = null, $strict = false, $debug = false)
139
- {
140
- if (is_null($storeId))
141
- {
142
- return $this->getProductAttributeSelectValue($attribute, $valueId, Mage_Core_Model_App::ADMIN_STORE_ID, true, $debug);
143
- }
144
-
145
- $attributeId = $attribute->getAttributeId();
146
-
147
- $sql = "SELECT optval.value
148
- FROM ".$this->getRes()->getTableName('eav/attribute_option')." opt
149
- INNER JOIN ".$this->getRes()->getTableName('eav/attribute_option_value')." optval ON opt.option_id=optval.option_id
150
- WHERE
151
- opt.option_id='".addslashes($valueId)."'
152
- AND
153
- opt.attribute_id = '".addslashes($attributeId)."'
154
- AND
155
- optval.store_id = '".addslashes($storeId)."'";
156
-
157
- if ($debug)
158
- var_dump($sql);
159
-
160
- $value = $this->getConnRead()->fetchCol($sql);
161
- if (is_array($value) && @$value[0] === null)
162
- $value = null;
163
- elseif (is_array($value) && isset($value[0]))
164
- $value = $value[0];
165
- else if (is_array($value) && count($value) == 0)
166
- $value = null;
167
-
168
- if (is_null($value) && $storeId != Mage_Core_Model_App::ADMIN_STORE_ID && $strict === false)
169
- {
170
- return $this->getProductAttributeSelectValue($attribute, $valueId, Mage_Core_Model_App::ADMIN_STORE_ID, true, $debug);
171
- }
172
-
173
- return $value;
174
- }
175
-
176
- /**
177
  * Get categories ids by product id.
178
  *
179
  * @param string $type_id
@@ -183,22 +439,22 @@ class Sooqr_Feed_Model_Tools extends Varien_Object
183
  */
184
  public function getCategoriesById($productId)
185
  {
186
- $data = false;
187
-
188
- $sql = "SELECT
189
- `category_id`
190
- FROM `".$this->getRes()->getTableName('catalog/category_product')."`
191
- WHERE
192
- `product_id`=\"".addslashes($productId)."\"";
193
- $result = $this->getConnRead()->fetchAll($sql);
194
-
195
- if ($result !== false)
196
- {
197
- $data = array();
198
- foreach ($result as $k => $row)
199
- $data[] = $row['category_id'];
200
- }
201
- return $data;
202
  }
203
 
204
  /**
@@ -207,147 +463,155 @@ class Sooqr_Feed_Model_Tools extends Varien_Object
207
  * @return array()
208
  */
209
  public function getProductInStoresIds($productId)
210
- {
211
- if (is_array($productId))
212
- {
213
- $value = array();
214
- foreach ($productId as $pid)
215
- $value[$pid] = array();
216
- }
217
-
218
- $sql = "SELECT ";
219
- if (is_array($productId))
220
- {
221
- $sql .= " pw.product_id AS 'product_id', s.store_id AS 'store_id'";
222
- }
223
- else
224
- {
225
- $sql .= " s.store_id ";
226
- }
227
- $sql .= " FROM ".$this->getRes()->getTableName('catalog/product_website')." AS pw
228
- INNER JOIN ".$this->getRes()->getTableName('core/store')." AS s
229
- ON s.website_id = pw.website_id
230
- WHERE";
231
- if (is_array($productId))
232
- {
233
- $sql .= " pw.product_id IN (\"".implode("\",\"", $productId)."\")";
234
- $rows = $this->getConnRead()->fetchAll($sql);
235
- foreach ($rows as $row)
236
- {
237
- if (!isset($value[$row['product_id']]))
238
- $value[$row['product_id']] = array();
239
- $value[$row['product_id']][] = $row['store_id'];
240
- }
241
- }
242
- else
243
- {
244
- $sql .= " pw.product_id=\"".addslashes($productId)."\"";
245
- $value = $this->getConnRead()->fetchCol($sql);
246
- }
247
-
248
- return $value;
249
- }
250
-
251
- /**
252
- * @param int $productId - parent product id
253
- * @return array
254
- */
255
- public function getChildsIds($productId)
256
- {
257
- $data = false;
258
- $sql = "SELECT
259
- `cpe`.`entity_id`
260
- FROM ".$this->getRes()->getTableName('catalog/product')." AS `cpe`
261
- INNER JOIN ".$this->getRes()->getTableName('catalog/product_super_link')." AS `cpsl`
262
- ON `cpe`.`entity_id`=`cpsl`.`product_id`
263
- INNER JOIN ".$this->getRes()->getTableName('catalog/product')." AS `cpe_parent`
264
- ON `cpsl`.`parent_id`=`cpe_parent`.`entity_id`
265
- WHERE
266
- `cpe_parent`.`entity_id`=\"".addslashes($productId)."\"";
267
- $result = $this->getConnRead()->fetchAll($sql);
268
-
269
- if ($result !== false)
270
- {
271
- foreach ($result as $row)
272
- {
273
- $data[] = $row['entity_id'];
274
- }
275
- }
276
-
277
- return $data;
278
- }
279
-
280
- /**
281
- * @param int $productId - parent product id
282
- * @return array
283
- */
284
- public function getConfigurableAttributeCodes($productId)
285
- {
286
- $data = false;
287
- $sql = "SELECT
288
- `eav`.`attribute_code`
289
- FROM ".$this->getRes()->getTableName('catalog/product_super_attribute')." AS `csa`
290
- INNER JOIN ".$this->getRes()->getTableName('eav/attribute')." AS `eav`
291
- ON `eav`.`attribute_id`=`csa`.`attribute_id`
292
- WHERE
293
- `csa`.`product_id`=\"".addslashes($productId)."\"";
294
- $result = $this->getConnRead()->fetchAll($sql);
295
-
296
- if ($result !== false)
297
- {
298
- foreach ($result as $row)
299
- {
300
- $data[] = $row['attribute_code'];
301
- }
302
- }
303
-
304
- return $data;
305
- }
306
-
307
- public function explodeMultiselectValue($value)
308
- {
309
- $arr = array();
310
- if (!empty($value))
311
- {
312
- $arr = explode(',', $value);
313
- foreach ($arr as $k => $v) $arr[$k] = trim($v);
314
- }
315
- return $arr;
316
- }
317
-
318
- /**
319
- * @return Mage_Core_Model_Resource
320
- */
321
- public function getRes()
322
  {
323
- if (is_null($this->_res))
324
- {
325
- $this->_res = Mage::getSingleton('core/resource');
326
- }
327
- return $this->_res;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
328
  }
329
 
330
  /**
331
- * @return Varien_Db_Adapter_Pdo_Mysql
332
- */
333
  public function getConnRead()
334
  {
335
- if (is_null($this->_conn_read))
336
- {
337
- $this->_conn_read = $this->getRes()->getConnection('core_read');
338
- }
339
- return $this->_conn_read;
340
  }
341
 
342
  /**
343
- * @return Varien_Db_Adapter_Pdo_Mysql
344
- */
345
  public function getConnWrite()
346
  {
347
- if (is_null($this->_conn_write))
348
- {
349
- $this->_conn_write = $this->getRes()->getConnection('core_write');
350
- }
351
- return $this->_conn_write;
 
 
 
 
 
 
 
 
352
  }
353
  }
25
 
26
  class Sooqr_Feed_Model_Tools extends Varien_Object
27
  {
28
+ static protected $html401NamedToNumeric = array(
29
+ '&nbsp;' => '&#160;', # no-break space = non-breaking space, U+00A0 ISOnum
30
+ '&iexcl;' => '&#161;', # inverted exclamation mark, U+00A1 ISOnum
31
+ '&cent;' => '&#162;', # cent sign, U+00A2 ISOnum
32
+ '&pound;' => '&#163;', # pound sign, U+00A3 ISOnum
33
+ '&curren;' => '&#164;', # currency sign, U+00A4 ISOnum
34
+ '&yen;' => '&#165;', # yen sign = yuan sign, U+00A5 ISOnum
35
+ '&brvbar;' => '&#166;', # broken bar = broken vertical bar, U+00A6 ISOnum
36
+ '&sect;' => '&#167;', # section sign, U+00A7 ISOnum
37
+ '&uml;' => '&#168;', # diaeresis = spacing diaeresis, U+00A8 ISOdia
38
+ '&copy;' => '&#169;', # copyright sign, U+00A9 ISOnum
39
+ '&ordf;' => '&#170;', # feminine ordinal indicator, U+00AA ISOnum
40
+ '&laquo;' => '&#171;', # left-pointing double angle quotation mark = left pointing guillemet, U+00AB ISOnum
41
+ '&not;' => '&#172;', # not sign, U+00AC ISOnum
42
+ '&shy;' => '&#173;', # soft hyphen = discretionary hyphen, U+00AD ISOnum
43
+ '&reg;' => '&#174;', # registered sign = registered trade mark sign, U+00AE ISOnum
44
+ '&macr;' => '&#175;', # macron = spacing macron = overline = APL overbar, U+00AF ISOdia
45
+ '&deg;' => '&#176;', # degree sign, U+00B0 ISOnum
46
+ '&plusmn;' => '&#177;', # plus-minus sign = plus-or-minus sign, U+00B1 ISOnum
47
+ '&sup2;' => '&#178;', # superscript two = superscript digit two = squared, U+00B2 ISOnum
48
+ '&sup3;' => '&#179;', # superscript three = superscript digit three = cubed, U+00B3 ISOnum
49
+ '&acute;' => '&#180;', # acute accent = spacing acute, U+00B4 ISOdia
50
+ '&micro;' => '&#181;', # micro sign, U+00B5 ISOnum
51
+ '&para;' => '&#182;', # pilcrow sign = paragraph sign, U+00B6 ISOnum
52
+ '&middot;' => '&#183;', # middle dot = Georgian comma = Greek middle dot, U+00B7 ISOnum
53
+ '&cedil;' => '&#184;', # cedilla = spacing cedilla, U+00B8 ISOdia
54
+ '&sup1;' => '&#185;', # superscript one = superscript digit one, U+00B9 ISOnum
55
+ '&ordm;' => '&#186;', # masculine ordinal indicator, U+00BA ISOnum
56
+ '&raquo;' => '&#187;', # right-pointing double angle quotation mark = right pointing guillemet, U+00BB ISOnum
57
+ '&frac14;' => '&#188;', # vulgar fraction one quarter = fraction one quarter, U+00BC ISOnum
58
+ '&frac12;' => '&#189;', # vulgar fraction one half = fraction one half, U+00BD ISOnum
59
+ '&frac34;' => '&#190;', # vulgar fraction three quarters = fraction three quarters, U+00BE ISOnum
60
+ '&iquest;' => '&#191;', # inverted question mark = turned question mark, U+00BF ISOnum
61
+ '&Agrave;' => '&#192;', # latin capital letter A with grave = latin capital letter A grave, U+00C0 ISOlat1
62
+ '&Aacute;' => '&#193;', # latin capital letter A with acute, U+00C1 ISOlat1
63
+ '&Acirc;' => '&#194;', # latin capital letter A with circumflex, U+00C2 ISOlat1
64
+ '&Atilde;' => '&#195;', # latin capital letter A with tilde, U+00C3 ISOlat1
65
+ '&Auml;' => '&#196;', # latin capital letter A with diaeresis, U+00C4 ISOlat1
66
+ '&Aring;' => '&#197;', # latin capital letter A with ring above = latin capital letter A ring, U+00C5 ISOlat1
67
+ '&AElig;' => '&#198;', # latin capital letter AE = latin capital ligature AE, U+00C6 ISOlat1
68
+ '&Ccedil;' => '&#199;', # latin capital letter C with cedilla, U+00C7 ISOlat1
69
+ '&Egrave;' => '&#200;', # latin capital letter E with grave, U+00C8 ISOlat1
70
+ '&Eacute;' => '&#201;', # latin capital letter E with acute, U+00C9 ISOlat1
71
+ '&Ecirc;' => '&#202;', # latin capital letter E with circumflex, U+00CA ISOlat1
72
+ '&Euml;' => '&#203;', # latin capital letter E with diaeresis, U+00CB ISOlat1
73
+ '&Igrave;' => '&#204;', # latin capital letter I with grave, U+00CC ISOlat1
74
+ '&Iacute;' => '&#205;', # latin capital letter I with acute, U+00CD ISOlat1
75
+ '&Icirc;' => '&#206;', # latin capital letter I with circumflex, U+00CE ISOlat1
76
+ '&Iuml;' => '&#207;', # latin capital letter I with diaeresis, U+00CF ISOlat1
77
+ '&ETH;' => '&#208;', # latin capital letter ETH, U+00D0 ISOlat1
78
+ '&Ntilde;' => '&#209;', # latin capital letter N with tilde, U+00D1 ISOlat1
79
+ '&Ograve;' => '&#210;', # latin capital letter O with grave, U+00D2 ISOlat1
80
+ '&Oacute;' => '&#211;', # latin capital letter O with acute, U+00D3 ISOlat1
81
+ '&Ocirc;' => '&#212;', # latin capital letter O with circumflex, U+00D4 ISOlat1
82
+ '&Otilde;' => '&#213;', # latin capital letter O with tilde, U+00D5 ISOlat1
83
+ '&Ouml;' => '&#214;', # latin capital letter O with diaeresis, U+00D6 ISOlat1
84
+ '&times;' => '&#215;', # multiplication sign, U+00D7 ISOnum
85
+ '&Oslash;' => '&#216;', # latin capital letter O with stroke = latin capital letter O slash, U+00D8 ISOlat1
86
+ '&Ugrave;' => '&#217;', # latin capital letter U with grave, U+00D9 ISOlat1
87
+ '&Uacute;' => '&#218;', # latin capital letter U with acute, U+00DA ISOlat1
88
+ '&Ucirc;' => '&#219;', # latin capital letter U with circumflex, U+00DB ISOlat1
89
+ '&Uuml;' => '&#220;', # latin capital letter U with diaeresis, U+00DC ISOlat1
90
+ '&Yacute;' => '&#221;', # latin capital letter Y with acute, U+00DD ISOlat1
91
+ '&THORN;' => '&#222;', # latin capital letter THORN, U+00DE ISOlat1
92
+ '&szlig;' => '&#223;', # latin small letter sharp s = ess-zed, U+00DF ISOlat1
93
+ '&agrave;' => '&#224;', # latin small letter a with grave = latin small letter a grave, U+00E0 ISOlat1
94
+ '&aacute;' => '&#225;', # latin small letter a with acute, U+00E1 ISOlat1
95
+ '&acirc;' => '&#226;', # latin small letter a with circumflex, U+00E2 ISOlat1
96
+ '&atilde;' => '&#227;', # latin small letter a with tilde, U+00E3 ISOlat1
97
+ '&auml;' => '&#228;', # latin small letter a with diaeresis, U+00E4 ISOlat1
98
+ '&aring;' => '&#229;', # latin small letter a with ring above = latin small letter a ring, U+00E5 ISOlat1
99
+ '&aelig;' => '&#230;', # latin small letter ae = latin small ligature ae, U+00E6 ISOlat1
100
+ '&ccedil;' => '&#231;', # latin small letter c with cedilla, U+00E7 ISOlat1
101
+ '&egrave;' => '&#232;', # latin small letter e with grave, U+00E8 ISOlat1
102
+ '&eacute;' => '&#233;', # latin small letter e with acute, U+00E9 ISOlat1
103
+ '&ecirc;' => '&#234;', # latin small letter e with circumflex, U+00EA ISOlat1
104
+ '&euml;' => '&#235;', # latin small letter e with diaeresis, U+00EB ISOlat1
105
+ '&igrave;' => '&#236;', # latin small letter i with grave, U+00EC ISOlat1
106
+ '&iacute;' => '&#237;', # latin small letter i with acute, U+00ED ISOlat1
107
+ '&icirc;' => '&#238;', # latin small letter i with circumflex, U+00EE ISOlat1
108
+ '&iuml;' => '&#239;', # latin small letter i with diaeresis, U+00EF ISOlat1
109
+ '&eth;' => '&#240;', # latin small letter eth, U+00F0 ISOlat1
110
+ '&ntilde;' => '&#241;', # latin small letter n with tilde, U+00F1 ISOlat1
111
+ '&ograve;' => '&#242;', # latin small letter o with grave, U+00F2 ISOlat1
112
+ '&oacute;' => '&#243;', # latin small letter o with acute, U+00F3 ISOlat1
113
+ '&ocirc;' => '&#244;', # latin small letter o with circumflex, U+00F4 ISOlat1
114
+ '&otilde;' => '&#245;', # latin small letter o with tilde, U+00F5 ISOlat1
115
+ '&ouml;' => '&#246;', # latin small letter o with diaeresis, U+00F6 ISOlat1
116
+ '&divide;' => '&#247;', # division sign, U+00F7 ISOnum
117
+ '&oslash;' => '&#248;', # latin small letter o with stroke, = latin small letter o slash, U+00F8 ISOlat1
118
+ '&ugrave;' => '&#249;', # latin small letter u with grave, U+00F9 ISOlat1
119
+ '&uacute;' => '&#250;', # latin small letter u with acute, U+00FA ISOlat1
120
+ '&ucirc;' => '&#251;', # latin small letter u with circumflex, U+00FB ISOlat1
121
+ '&uuml;' => '&#252;', # latin small letter u with diaeresis, U+00FC ISOlat1
122
+ '&yacute;' => '&#253;', # latin small letter y with acute, U+00FD ISOlat1
123
+ '&thorn;' => '&#254;', # latin small letter thorn, U+00FE ISOlat1
124
+ '&yuml;' => '&#255;', # latin small letter y with diaeresis, U+00FF ISOlat1
125
+ '&fnof;' => '&#402;', # latin small f with hook = function = florin, U+0192 ISOtech
126
+ '&Alpha;' => '&#913;', # greek capital letter alpha, U+0391
127
+ '&Beta;' => '&#914;', # greek capital letter beta, U+0392
128
+ '&Gamma;' => '&#915;', # greek capital letter gamma, U+0393 ISOgrk3
129
+ '&Delta;' => '&#916;', # greek capital letter delta, U+0394 ISOgrk3
130
+ '&Epsilon;' => '&#917;', # greek capital letter epsilon, U+0395
131
+ '&Zeta;' => '&#918;', # greek capital letter zeta, U+0396
132
+ '&Eta;' => '&#919;', # greek capital letter eta, U+0397
133
+ '&Theta;' => '&#920;', # greek capital letter theta, U+0398 ISOgrk3
134
+ '&Iota;' => '&#921;', # greek capital letter iota, U+0399
135
+ '&Kappa;' => '&#922;', # greek capital letter kappa, U+039A
136
+ '&Lambda;' => '&#923;', # greek capital letter lambda, U+039B ISOgrk3
137
+ '&Mu;' => '&#924;', # greek capital letter mu, U+039C
138
+ '&Nu;' => '&#925;', # greek capital letter nu, U+039D
139
+ '&Xi;' => '&#926;', # greek capital letter xi, U+039E ISOgrk3
140
+ '&Omicron;' => '&#927;', # greek capital letter omicron, U+039F
141
+ '&Pi;' => '&#928;', # greek capital letter pi, U+03A0 ISOgrk3
142
+ '&Rho;' => '&#929;', # greek capital letter rho, U+03A1
143
+ '&Sigma;' => '&#931;', # greek capital letter sigma, U+03A3 ISOgrk3
144
+ '&Tau;' => '&#932;', # greek capital letter tau, U+03A4
145
+ '&Upsilon;' => '&#933;', # greek capital letter upsilon, U+03A5 ISOgrk3
146
+ '&Phi;' => '&#934;', # greek capital letter phi, U+03A6 ISOgrk3
147
+ '&Chi;' => '&#935;', # greek capital letter chi, U+03A7
148
+ '&Psi;' => '&#936;', # greek capital letter psi, U+03A8 ISOgrk3
149
+ '&Omega;' => '&#937;', # greek capital letter omega, U+03A9 ISOgrk3
150
+ '&alpha;' => '&#945;', # greek small letter alpha, U+03B1 ISOgrk3
151
+ '&beta;' => '&#946;', # greek small letter beta, U+03B2 ISOgrk3
152
+ '&gamma;' => '&#947;', # greek small letter gamma, U+03B3 ISOgrk3
153
+ '&delta;' => '&#948;', # greek small letter delta, U+03B4 ISOgrk3
154
+ '&epsilon;' => '&#949;', # greek small letter epsilon, U+03B5 ISOgrk3
155
+ '&zeta;' => '&#950;', # greek small letter zeta, U+03B6 ISOgrk3
156
+ '&eta;' => '&#951;', # greek small letter eta, U+03B7 ISOgrk3
157
+ '&theta;' => '&#952;', # greek small letter theta, U+03B8 ISOgrk3
158
+ '&iota;' => '&#953;', # greek small letter iota, U+03B9 ISOgrk3
159
+ '&kappa;' => '&#954;', # greek small letter kappa, U+03BA ISOgrk3
160
+ '&lambda;' => '&#955;', # greek small letter lambda, U+03BB ISOgrk3
161
+ '&mu;' => '&#956;', # greek small letter mu, U+03BC ISOgrk3
162
+ '&nu;' => '&#957;', # greek small letter nu, U+03BD ISOgrk3
163
+ '&xi;' => '&#958;', # greek small letter xi, U+03BE ISOgrk3
164
+ '&omicron;' => '&#959;', # greek small letter omicron, U+03BF NEW
165
+ '&pi;' => '&#960;', # greek small letter pi, U+03C0 ISOgrk3
166
+ '&rho;' => '&#961;', # greek small letter rho, U+03C1 ISOgrk3
167
+ '&sigmaf;' => '&#962;', # greek small letter final sigma, U+03C2 ISOgrk3
168
+ '&sigma;' => '&#963;', # greek small letter sigma, U+03C3 ISOgrk3
169
+ '&tau;' => '&#964;', # greek small letter tau, U+03C4 ISOgrk3
170
+ '&upsilon;' => '&#965;', # greek small letter upsilon, U+03C5 ISOgrk3
171
+ '&phi;' => '&#966;', # greek small letter phi, U+03C6 ISOgrk3
172
+ '&chi;' => '&#967;', # greek small letter chi, U+03C7 ISOgrk3
173
+ '&psi;' => '&#968;', # greek small letter psi, U+03C8 ISOgrk3
174
+ '&omega;' => '&#969;', # greek small letter omega, U+03C9 ISOgrk3
175
+ '&thetasym;' => '&#977;', # greek small letter theta symbol, U+03D1 NEW
176
+ '&upsih;' => '&#978;', # greek upsilon with hook symbol, U+03D2 NEW
177
+ '&piv;' => '&#982;', # greek pi symbol, U+03D6 ISOgrk3
178
+ '&bull;' => '&#8226;', # bullet = black small circle, U+2022 ISOpub
179
+ '&hellip;' => '&#8230;', # horizontal ellipsis = three dot leader, U+2026 ISOpub
180
+ '&prime;' => '&#8242;', # prime = minutes = feet, U+2032 ISOtech
181
+ '&Prime;' => '&#8243;', # double prime = seconds = inches, U+2033 ISOtech
182
+ '&oline;' => '&#8254;', # overline = spacing overscore, U+203E NEW
183
+ '&frasl;' => '&#8260;', # fraction slash, U+2044 NEW
184
+ '&weierp;' => '&#8472;', # script capital P = power set = Weierstrass p, U+2118 ISOamso
185
+ '&image;' => '&#8465;', # blackletter capital I = imaginary part, U+2111 ISOamso
186
+ '&real;' => '&#8476;', # blackletter capital R = real part symbol, U+211C ISOamso
187
+ '&trade;' => '&#8482;', # trade mark sign, U+2122 ISOnum
188
+ '&alefsym;' => '&#8501;', # alef symbol = first transfinite cardinal, U+2135 NEW
189
+ '&larr;' => '&#8592;', # leftwards arrow, U+2190 ISOnum
190
+ '&uarr;' => '&#8593;', # upwards arrow, U+2191 ISOnum
191
+ '&rarr;' => '&#8594;', # rightwards arrow, U+2192 ISOnum
192
+ '&darr;' => '&#8595;', # downwards arrow, U+2193 ISOnum
193
+ '&harr;' => '&#8596;', # left right arrow, U+2194 ISOamsa
194
+ '&crarr;' => '&#8629;', # downwards arrow with corner leftwards = carriage return, U+21B5 NEW
195
+ '&lArr;' => '&#8656;', # leftwards double arrow, U+21D0 ISOtech
196
+ '&uArr;' => '&#8657;', # upwards double arrow, U+21D1 ISOamsa
197
+ '&rArr;' => '&#8658;', # rightwards double arrow, U+21D2 ISOtech
198
+ '&dArr;' => '&#8659;', # downwards double arrow, U+21D3 ISOamsa
199
+ '&hArr;' => '&#8660;', # left right double arrow, U+21D4 ISOamsa
200
+ '&forall;' => '&#8704;', # for all, U+2200 ISOtech
201
+ '&part;' => '&#8706;', # partial differential, U+2202 ISOtech
202
+ '&exist;' => '&#8707;', # there exists, U+2203 ISOtech
203
+ '&empty;' => '&#8709;', # empty set = null set = diameter, U+2205 ISOamso
204
+ '&nabla;' => '&#8711;', # nabla = backward difference, U+2207 ISOtech
205
+ '&isin;' => '&#8712;', # element of, U+2208 ISOtech
206
+ '&notin;' => '&#8713;', # not an element of, U+2209 ISOtech
207
+ '&ni;' => '&#8715;', # contains as member, U+220B ISOtech
208
+ '&prod;' => '&#8719;', # n-ary product = product sign, U+220F ISOamsb
209
+ '&sum;' => '&#8721;', # n-ary sumation, U+2211 ISOamsb
210
+ '&minus;' => '&#8722;', # minus sign, U+2212 ISOtech
211
+ '&lowast;' => '&#8727;', # asterisk operator, U+2217 ISOtech
212
+ '&radic;' => '&#8730;', # square root = radical sign, U+221A ISOtech
213
+ '&prop;' => '&#8733;', # proportional to, U+221D ISOtech
214
+ '&infin;' => '&#8734;', # infinity, U+221E ISOtech
215
+ '&ang;' => '&#8736;', # angle, U+2220 ISOamso
216
+ '&and;' => '&#8743;', # logical and = wedge, U+2227 ISOtech
217
+ '&or;' => '&#8744;', # logical or = vee, U+2228 ISOtech
218
+ '&cap;' => '&#8745;', # intersection = cap, U+2229 ISOtech
219
+ '&cup;' => '&#8746;', # union = cup, U+222A ISOtech
220
+ '&int;' => '&#8747;', # integral, U+222B ISOtech
221
+ '&there4;' => '&#8756;', # therefore, U+2234 ISOtech
222
+ '&sim;' => '&#8764;', # tilde operator = varies with = similar to, U+223C ISOtech
223
+ '&cong;' => '&#8773;', # approximately equal to, U+2245 ISOtech
224
+ '&asymp;' => '&#8776;', # almost equal to = asymptotic to, U+2248 ISOamsr
225
+ '&ne;' => '&#8800;', # not equal to, U+2260 ISOtech
226
+ '&equiv;' => '&#8801;', # identical to, U+2261 ISOtech
227
+ '&le;' => '&#8804;', # less-than or equal to, U+2264 ISOtech
228
+ '&ge;' => '&#8805;', # greater-than or equal to, U+2265 ISOtech
229
+ '&sub;' => '&#8834;', # subset of, U+2282 ISOtech
230
+ '&sup;' => '&#8835;', # superset of, U+2283 ISOtech
231
+ '&nsub;' => '&#8836;', # not a subset of, U+2284 ISOamsn
232
+ '&sube;' => '&#8838;', # subset of or equal to, U+2286 ISOtech
233
+ '&supe;' => '&#8839;', # superset of or equal to, U+2287 ISOtech
234
+ '&oplus;' => '&#8853;', # circled plus = direct sum, U+2295 ISOamsb
235
+ '&otimes;' => '&#8855;', # circled times = vector product, U+2297 ISOamsb
236
+ '&perp;' => '&#8869;', # up tack = orthogonal to = perpendicular, U+22A5 ISOtech
237
+ '&sdot;' => '&#8901;', # dot operator, U+22C5 ISOamsb
238
+ '&lceil;' => '&#8968;', # left ceiling = apl upstile, U+2308 ISOamsc
239
+ '&rceil;' => '&#8969;', # right ceiling, U+2309 ISOamsc
240
+ '&lfloor;' => '&#8970;', # left floor = apl downstile, U+230A ISOamsc
241
+ '&rfloor;' => '&#8971;', # right floor, U+230B ISOamsc
242
+ '&lang;' => '&#9001;', # left-pointing angle bracket = bra, U+2329 ISOtech
243
+ '&rang;' => '&#9002;', # right-pointing angle bracket = ket, U+232A ISOtech
244
+ '&loz;' => '&#9674;', # lozenge, U+25CA ISOpub
245
+ '&spades;' => '&#9824;', # black spade suit, U+2660 ISOpub
246
+ '&clubs;' => '&#9827;', # black club suit = shamrock, U+2663 ISOpub
247
+ '&hearts;' => '&#9829;', # black heart suit = valentine, U+2665 ISOpub
248
+ '&diams;' => '&#9830;', # black diamond suit, U+2666 ISOpub
249
+ '&quot;' => '&#34;', # quotation mark = APL quote, U+0022 ISOnum
250
+ '&amp;' => '&#38;', # ampersand, U+0026 ISOnum
251
+ '&lt;' => '&#60;', # less-than sign, U+003C ISOnum
252
+ '&gt;' => '&#62;', # greater-than sign, U+003E ISOnum
253
+ '&OElig;' => '&#338;', # latin capital ligature OE, U+0152 ISOlat2
254
+ '&oelig;' => '&#339;', # latin small ligature oe, U+0153 ISOlat2
255
+ '&Scaron;' => '&#352;', # latin capital letter S with caron, U+0160 ISOlat2
256
+ '&scaron;' => '&#353;', # latin small letter s with caron, U+0161 ISOlat2
257
+ '&Yuml;' => '&#376;', # latin capital letter Y with diaeresis, U+0178 ISOlat2
258
+ '&circ;' => '&#710;', # modifier letter circumflex accent, U+02C6 ISOpub
259
+ '&tilde;' => '&#732;', # small tilde, U+02DC ISOdia
260
+ '&ensp;' => '&#8194;', # en space, U+2002 ISOpub
261
+ '&emsp;' => '&#8195;', # em space, U+2003 ISOpub
262
+ '&thinsp;' => '&#8201;', # thin space, U+2009 ISOpub
263
+ '&zwnj;' => '&#8204;', # zero width non-joiner, U+200C NEW RFC 2070
264
+ '&zwj;' => '&#8205;', # zero width joiner, U+200D NEW RFC 2070
265
+ '&lrm;' => '&#8206;', # left-to-right mark, U+200E NEW RFC 2070
266
+ '&rlm;' => '&#8207;', # right-to-left mark, U+200F NEW RFC 2070
267
+ '&ndash;' => '&#8211;', # en dash, U+2013 ISOpub
268
+ '&mdash;' => '&#8212;', # em dash, U+2014 ISOpub
269
+ '&lsquo;' => '&#8216;', # left single quotation mark, U+2018 ISOnum
270
+ '&rsquo;' => '&#8217;', # right single quotation mark, U+2019 ISOnum
271
+ '&sbquo;' => '&#8218;', # single low-9 quotation mark, U+201A NEW
272
+ '&ldquo;' => '&#8220;', # left double quotation mark, U+201C ISOnum
273
+ '&rdquo;' => '&#8221;', # right double quotation mark, U+201D ISOnum
274
+ '&bdquo;' => '&#8222;', # double low-9 quotation mark, U+201E NEW
275
+ '&dagger;' => '&#8224;', # dagger, U+2020 ISOpub
276
+ '&Dagger;' => '&#8225;', # double dagger, U+2021 ISOpub
277
+ '&permil;' => '&#8240;', # per mille sign, U+2030 ISOtech
278
+ '&lsaquo;' => '&#8249;', # single left-pointing angle quotation mark, U+2039 ISO proposed
279
+ '&rsaquo;' => '&#8250;', # single right-pointing angle quotation mark, U+203A ISO proposed
280
+ '&euro;' => '&#8364;', # euro sign, U+20AC NEW
281
+ '&apos;' => '&#39;', # apostrophe = APL quote, U+0027 ISOnum
282
+ );
283
+
284
+ public function _construct()
285
+ {
286
+ parent::_construct();
287
+ $this->loadEntityType('catalog_product');
288
+ }
289
+
290
+ public function loadEntityType($type)
291
  {
292
+ if (is_array($type))
293
+ {
294
+ foreach ($type as $t)
295
+ if (is_string($t))
296
+ $this->loadEntityType($t);
297
+ }
298
+ else
299
+ {
300
+ $entityType = Mage::getModel('eav/config')->getEntityType('catalog_product');
301
+
302
+ Mage::register('feed/entity_type/'.$type, $entityType);
303
+ }
304
  return $this;
305
  }
306
 
307
  public function getEntityType($type)
308
  {
309
+ return Mage::registry('feed/entity_type/'.$type);
310
+ }
311
+
312
+ public function getProductAttributeValueBySql($attribute, $type = "text", $productId, $storeId = null, $strict = false, $debug = false)
313
+ {
314
+ if (array_search($type, array('text', 'int', 'decimal', 'varchar', 'datetime')) === false)
315
+ {
316
+ Mage::throwException(sprintf("Unknown attribute backend type %s for attribute code %s.", $type, $attribute->getAttributeCode()));
317
+ }
318
+
319
+ if (is_null($storeId))
320
+ {
321
+ return $this->getProductAttributeValueBySql($attribute, $type, $productId, Mage_Core_Model_App::ADMIN_STORE_ID, true, $debug);
322
+ }
323
+
324
+ $attributeId = $attribute->getAttributeId();
325
+
326
+ $sql = "SELECT val.value
327
+ FROM ".$this->getRes()->getTableName('catalog/product')."_".$type." val
328
+ INNER JOIN ".$this->getRes()->getTableName('eav/attribute')." eav ON val.attribute_id=eav.attribute_id
329
+ WHERE
330
+ val.entity_id='".addslashes($productId)."'
331
+ AND
332
+ val.entity_type_id = ".$this->getEntityType('catalog_product')->getEntityTypeId()."
333
+ AND
334
+ val.store_id = '".addslashes($storeId)."'
335
+ AND
336
+ val.attribute_id = '".addslashes($attributeId)."'";
337
+ if ($debug)
338
+ var_dump($sql);
339
+ $value = $this->getConnRead()->fetchCol($sql);
340
+ if (is_array($value) && @$value[0] === null)
341
+ $value = null;
342
+ elseif (is_array($value) && isset($value[0]))
343
+ $value = $value[0];
344
+ else if (is_array($value) && count($value) == 0)
345
+ $value = null;
346
+
347
+ if (is_null($value) && $storeId != Mage_Core_Model_App::ADMIN_STORE_ID && $strict === false)
348
+ {
349
+ return $this->getProductAttributeValueBySql($attribute, $type, $productId, Mage_Core_Model_App::ADMIN_STORE_ID, true, $debug);
350
+ }
351
+
352
+ return $value;
353
  }
354
+
355
+ /**
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
356
  * Check if there is a parent of type (configurable, ..)
357
  *
358
  * @param string $type_id
362
  */
363
  public function isChildOfProductType($type_id, $sku, $parent_type_id)
364
  {
365
+ $data = false;
366
+
367
+ if ($type_id != Mage_Catalog_Model_Product_Type::TYPE_SIMPLE)
368
+ return $data;
369
+
370
+ $sql = "SELECT
371
+ `cpe`.`entity_id` AS 'entity_id',
372
+ `cpe`.`sku` AS 'sku',
373
+ `cpe_parent`.`entity_id` AS 'parent_entity_id',
374
+ `cpe_parent`.`sku` AS 'parent_sku'
375
+ FROM `".$this->getRes()->getTableName('catalog/product')."` AS `cpe`
376
+ INNER JOIN `".$this->getRes()->getTableName('catalog/product_super_link')."` AS `cpsl`
377
+ ON `cpe`.`entity_id`=`cpsl`.`product_id`
378
+ INNER JOIN `".$this->getRes()->getTableName('catalog/product')."` AS `cpe_parent`
379
+ ON `cpsl`.`parent_id`=`cpe_parent`.`entity_id`
380
+ WHERE
381
+ `cpe`.`sku`=\"".addslashes($sku)."\"
382
+ AND
383
+ `cpe_parent`.`type_id`=\"".addslashes($parent_type_id)."\"";
384
+ $result = $this->getConnRead()->fetchRow($sql);
385
+
386
+ if ($result !== false)
387
+ {
388
+ $data = $result;
389
+ }
390
+
391
+ return $data;
392
  }
393
 
394
  public function getProductAttributeSelectValue($attribute, $valueId, $storeId = null, $strict = false, $debug = false)
395
+ {
396
+ if (is_null($storeId))
397
+ {
398
+ return $this->getProductAttributeSelectValue($attribute, $valueId, Mage_Core_Model_App::ADMIN_STORE_ID, true, $debug);
399
+ }
400
+
401
+ $attributeId = $attribute->getAttributeId();
402
+
403
+ $sql = "SELECT optval.value
404
+ FROM ".$this->getRes()->getTableName('eav/attribute_option')." opt
405
+ INNER JOIN ".$this->getRes()->getTableName('eav/attribute_option_value')." optval ON opt.option_id=optval.option_id
406
+ WHERE
407
+ opt.option_id='".addslashes($valueId)."'
408
+ AND
409
+ opt.attribute_id = '".addslashes($attributeId)."'
410
+ AND
411
+ optval.store_id = '".addslashes($storeId)."'";
412
+
413
+ if ($debug)
414
+ var_dump($sql);
415
+
416
+ $value = $this->getConnRead()->fetchCol($sql);
417
+ if (is_array($value) && @$value[0] === null)
418
+ $value = null;
419
+ elseif (is_array($value) && isset($value[0]))
420
+ $value = $value[0];
421
+ else if (is_array($value) && count($value) == 0)
422
+ $value = null;
423
+
424
+ if (is_null($value) && $storeId != Mage_Core_Model_App::ADMIN_STORE_ID && $strict === false)
425
+ {
426
+ return $this->getProductAttributeSelectValue($attribute, $valueId, Mage_Core_Model_App::ADMIN_STORE_ID, true, $debug);
427
+ }
428
+
429
+ return $value;
430
+ }
431
+
432
+ /**
433
  * Get categories ids by product id.
434
  *
435
  * @param string $type_id
439
  */
440
  public function getCategoriesById($productId)
441
  {
442
+ $data = false;
443
+
444
+ $sql = "SELECT
445
+ `category_id`
446
+ FROM `".$this->getRes()->getTableName('catalog/category_product')."`
447
+ WHERE
448
+ `product_id`=\"".addslashes($productId)."\"";
449
+ $result = $this->getConnRead()->fetchAll($sql);
450
+
451
+ if ($result !== false)
452
+ {
453
+ $data = array();
454
+ foreach ($result as $k => $row)
455
+ $data[] = $row['category_id'];
456
+ }
457
+ return $data;
458
  }
459
 
460
  /**
463
  * @return array()
464
  */
465
  public function getProductInStoresIds($productId)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
466
  {
467
+ if (is_array($productId))
468
+ {
469
+ $value = array();
470
+ foreach ($productId as $pid)
471
+ $value[$pid] = array();
472
+ }
473
+
474
+ $sql = "SELECT ";
475
+ if (is_array($productId))
476
+ {
477
+ $sql .= " pw.product_id AS 'product_id', s.store_id AS 'store_id'";
478
+ }
479
+ else
480
+ {
481
+ $sql .= " s.store_id ";
482
+ }
483
+ $sql .= " FROM ".$this->getRes()->getTableName('catalog/product_website')." AS pw
484
+ INNER JOIN ".$this->getRes()->getTableName('core/store')." AS s
485
+ ON s.website_id = pw.website_id
486
+ WHERE";
487
+ if (is_array($productId))
488
+ {
489
+ $sql .= " pw.product_id IN (\"".implode("\",\"", $productId)."\")";
490
+ $rows = $this->getConnRead()->fetchAll($sql);
491
+ foreach ($rows as $row)
492
+ {
493
+ if (!isset($value[$row['product_id']]))
494
+ $value[$row['product_id']] = array();
495
+ $value[$row['product_id']][] = $row['store_id'];
496
+ }
497
+ }
498
+ else
499
+ {
500
+ $sql .= " pw.product_id=\"".addslashes($productId)."\"";
501
+ $value = $this->getConnRead()->fetchCol($sql);
502
+ }
503
+
504
+ return $value;
505
+ }
506
+
507
+ /**
508
+ * @param int $productId - parent product id
509
+ * @return array
510
+ */
511
+ public function getChildsIds($productId)
512
+ {
513
+ $data = false;
514
+ $sql = "SELECT
515
+ `cpe`.`entity_id`
516
+ FROM ".$this->getRes()->getTableName('catalog/product')." AS `cpe`
517
+ INNER JOIN ".$this->getRes()->getTableName('catalog/product_super_link')." AS `cpsl`
518
+ ON `cpe`.`entity_id`=`cpsl`.`product_id`
519
+ INNER JOIN ".$this->getRes()->getTableName('catalog/product')." AS `cpe_parent`
520
+ ON `cpsl`.`parent_id`=`cpe_parent`.`entity_id`
521
+ WHERE
522
+ `cpe_parent`.`entity_id`=\"".addslashes($productId)."\"";
523
+ $result = $this->getConnRead()->fetchAll($sql);
524
+
525
+ if ($result !== false)
526
+ {
527
+ foreach ($result as $row)
528
+ {
529
+ $data[] = $row['entity_id'];
530
+ }
531
+ }
532
+
533
+ return $data;
534
+ }
535
+
536
+ /**
537
+ * @param int $productId - parent product id
538
+ * @return array
539
+ */
540
+ public function getConfigurableAttributeCodes($productId)
541
+ {
542
+ $data = false;
543
+ $sql = "SELECT
544
+ `eav`.`attribute_code`
545
+ FROM ".$this->getRes()->getTableName('catalog/product_super_attribute')." AS `csa`
546
+ INNER JOIN ".$this->getRes()->getTableName('eav/attribute')." AS `eav`
547
+ ON `eav`.`attribute_id`=`csa`.`attribute_id`
548
+ WHERE
549
+ `csa`.`product_id`=\"".addslashes($productId)."\"";
550
+ $result = $this->getConnRead()->fetchAll($sql);
551
+
552
+ if ($result !== false)
553
+ {
554
+ foreach ($result as $row)
555
+ {
556
+ $data[] = $row['attribute_code'];
557
+ }
558
+ }
559
+
560
+ return $data;
561
+ }
562
+
563
+ public function explodeMultiselectValue($value)
564
+ {
565
+ $arr = array();
566
+ if (!empty($value))
567
+ {
568
+ $arr = explode(',', $value);
569
+ foreach ($arr as $k => $v) $arr[$k] = trim($v);
570
+ }
571
+ return $arr;
572
+ }
573
+
574
+ /**
575
+ * @return Mage_Core_Model_Resource
576
+ */
577
+ public function getRes()
578
+ {
579
+ if (is_null($this->_res))
580
+ {
581
+ $this->_res = Mage::getSingleton('core/resource');
582
+ }
583
+ return $this->_res;
584
  }
585
 
586
  /**
587
+ * @return Varien_Db_Adapter_Pdo_Mysql
588
+ */
589
  public function getConnRead()
590
  {
591
+ if (is_null($this->_conn_read))
592
+ {
593
+ $this->_conn_read = $this->getRes()->getConnection('core_read');
594
+ }
595
+ return $this->_conn_read;
596
  }
597
 
598
  /**
599
+ * @return Varien_Db_Adapter_Pdo_Mysql
600
+ */
601
  public function getConnWrite()
602
  {
603
+ if (is_null($this->_conn_write))
604
+ {
605
+ $this->_conn_write = $this->getRes()->getConnection('core_write');
606
+ }
607
+ return $this->_conn_write;
608
+ }
609
+
610
+ /**
611
+ *
612
+ */
613
+ static public function convertEntities($str)
614
+ {
615
+ return strtr($str, self::$html401NamedToNumeric);
616
  }
617
  }
app/code/community/Sooqr/Feed/controllers/IndexController.php CHANGED
@@ -13,7 +13,8 @@ class Sooqr_Feed_IndexController extends Mage_Core_Controller_Front_Action
13
  $limit = $this->getRequest()->getParam('limit');
14
  $debug = $this->getRequest()->getParam('debug');
15
  $reload = $this->getRequest()->getParam('reload');
16
-
 
17
  // Use the store_code GET parameter to overrule the current store_code
18
  if (is_null($storeCode = $this->getRequest()->getParam('store_code')))
19
  {
@@ -22,8 +23,7 @@ class Sooqr_Feed_IndexController extends Mage_Core_Controller_Front_Action
22
  {
23
  $storeCode = Mage_Core_Model_Store::DEFAULT_CODE;
24
  }
25
- }
26
-
27
  $model = Mage::getSingleton('feed/generator', array(
28
  'cli_mode' => false,
29
  'limit' => is_numeric($limit) ? (int)$limit : null,
13
  $limit = $this->getRequest()->getParam('limit');
14
  $debug = $this->getRequest()->getParam('debug');
15
  $reload = $this->getRequest()->getParam('reload');
16
+
17
+
18
  // Use the store_code GET parameter to overrule the current store_code
19
  if (is_null($storeCode = $this->getRequest()->getParam('store_code')))
20
  {
23
  {
24
  $storeCode = Mage_Core_Model_Store::DEFAULT_CODE;
25
  }
26
+ }
 
27
  $model = Mage::getSingleton('feed/generator', array(
28
  'cli_mode' => false,
29
  'limit' => is_numeric($limit) ? (int)$limit : null,
app/code/community/Sooqr/Feed/etc/config.xml CHANGED
@@ -2,7 +2,7 @@
2
  <config>
3
  <modules>
4
  <Sooqr_Feed>
5
- <version>1.0.4.4</version>
6
  </Sooqr_Feed>
7
  </modules>
8
  <frontend>
@@ -45,6 +45,8 @@
45
  <price_in_grouped_group>total</price_in_grouped_group>
46
  <custom_field_map backend_model="feed/system_config_backend_serialized_customfieldmap" />
47
  <batch_size>1000</batch_size>
 
 
48
  <product_types>simple,bundle,configurable,downloadable,grouped,virtual</product_types>
49
 
50
  <max_description_length>1000</max_description_length>
2
  <config>
3
  <modules>
4
  <Sooqr_Feed>
5
+ <version>1.0.5</version>
6
  </Sooqr_Feed>
7
  </modules>
8
  <frontend>
45
  <price_in_grouped_group>total</price_in_grouped_group>
46
  <custom_field_map backend_model="feed/system_config_backend_serialized_customfieldmap" />
47
  <batch_size>1000</batch_size>
48
+ <thumbnail_size>120x120</thumbnail_size>
49
+ <sales_volume_period>30</sales_volume_period>
50
  <product_types>simple,bundle,configurable,downloadable,grouped,virtual</product_types>
51
 
52
  <max_description_length>1000</max_description_length>
app/code/community/Sooqr/Feed/etc/system.xml CHANGED
@@ -15,6 +15,7 @@
15
  <sort_order>100</sort_order>
16
  <show_in_default>1</show_in_default>
17
  <show_in_website>1</show_in_website>
 
18
  <fields>
19
  <enabled translate="label comment">
20
  <label>Enable feed</label>
@@ -24,6 +25,7 @@
24
  <sort_order>10</sort_order>
25
  <show_in_default>1</show_in_default>
26
  <show_in_website>1</show_in_website>
 
27
  </enabled>
28
  <product_types translate="label">
29
  <label>Exported product types</label>
@@ -99,12 +101,13 @@
99
  </price_in_grouped_group>
100
  <background_mode translate="label comment">
101
  <label>Enable background mode</label>
102
- <comment><![CDATA[ For large sites, feed generation should be run from the command line ]]></comment>
103
  <frontend_type>select</frontend_type>
104
  <source_model>adminhtml/system_config_source_yesno</source_model>
105
  <sort_order>70</sort_order>
106
  <show_in_default>1</show_in_default>
107
  <show_in_website>1</show_in_website>
 
108
  </background_mode>
109
  <batch_size translate="label comment">
110
  <label>Batch size</label>
@@ -113,6 +116,7 @@
113
  <sort_order>80</sort_order>
114
  <show_in_default>1</show_in_default>
115
  <show_in_website>1</show_in_website>
 
116
  </batch_size>
117
  </fields>
118
  </feed>
15
  <sort_order>100</sort_order>
16
  <show_in_default>1</show_in_default>
17
  <show_in_website>1</show_in_website>
18
+ <show_in_store>1</show_in_store>
19
  <fields>
20
  <enabled translate="label comment">
21
  <label>Enable feed</label>
25
  <sort_order>10</sort_order>
26
  <show_in_default>1</show_in_default>
27
  <show_in_website>1</show_in_website>
28
+ <show_in_store>1</show_in_store>
29
  </enabled>
30
  <product_types translate="label">
31
  <label>Exported product types</label>
101
  </price_in_grouped_group>
102
  <background_mode translate="label comment">
103
  <label>Enable background mode</label>
104
+ <comment><![CDATA[ For large sites, feed generation should be run from the command line. Setting this option to yes doesn't generate the feed from the command line automatic. Ask the Sooqr support how. ]]></comment>
105
  <frontend_type>select</frontend_type>
106
  <source_model>adminhtml/system_config_source_yesno</source_model>
107
  <sort_order>70</sort_order>
108
  <show_in_default>1</show_in_default>
109
  <show_in_website>1</show_in_website>
110
+ <show_in_store>1</show_in_store>
111
  </background_mode>
112
  <batch_size translate="label comment">
113
  <label>Batch size</label>
116
  <sort_order>80</sort_order>
117
  <show_in_default>1</show_in_default>
118
  <show_in_website>1</show_in_website>
119
+ <show_in_store>1</show_in_store>
120
  </batch_size>
121
  </fields>
122
  </feed>
app/code/community/Sooqr/Feed/scripts/generate_sooqr_feed.php CHANGED
@@ -31,14 +31,14 @@ if (isset($argv[1]))
31
  }
32
  else
33
  {
34
- // If required, replace Mage_Core_Model_Store::DEFAULT_CODE with your 'storecode'.
35
  $storeCode = Mage_Core_Model_Store::DEFAULT_CODE;
36
  }
37
 
38
  Mage::app('admin')->setUseSessionInUrl(false);
39
 
40
  $feedGenerator = Mage::getSingleton('feed/generator', array(
41
- 'cli_mode' => true,
42
  'store_code' => $storeCode,
43
  ));
44
  $feedGenerator->run();
31
  }
32
  else
33
  {
34
+ // If required, replace Mage_Core_Model_Store::DEFAULT_CODE with your 'storecode'.
35
  $storeCode = Mage_Core_Model_Store::DEFAULT_CODE;
36
  }
37
 
38
  Mage::app('admin')->setUseSessionInUrl(false);
39
 
40
  $feedGenerator = Mage::getSingleton('feed/generator', array(
41
+ 'cli_mode' => true,
42
  'store_code' => $storeCode,
43
  ));
44
  $feedGenerator->run();
app/code/community/Sooqr/Feed/scripts/generate_sooqr_feed2.php ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once dirname(__FILE__) . '/../../../../../../app/Mage.php';
4
+
5
+ set_time_limit(0);
6
+ /* Setting memory limit depends on the number of products exported.*/
7
+ /*ini_set('memory_limit','600M');*/
8
+ error_reporting(E_ALL);
9
+
10
+ if (!Mage::isInstalled())
11
+ {
12
+ echo 'Application is not installed yet, please complete install wizard first.';
13
+ exit;
14
+ }
15
+
16
+ $_SERVER['SCRIPT_NAME'] = str_replace(basename(__FILE__), 'index.php', $_SERVER['SCRIPT_NAME']);
17
+ $_SERVER['SCRIPT_FILENAME'] = str_replace(basename(__FILE__), 'index.php', $_SERVER['SCRIPT_FILENAME']);
18
+
19
+ // Show simple usage help
20
+ if (isset($argv[1])
21
+ && ($argv[1] == '-h'
22
+ || $argv[1] == '--help'))
23
+ {
24
+ printf('Usage: %s <store-code>'."\n", basename(__FILE__));
25
+ die;
26
+ }
27
+
28
+ if (isset($argv[1]))
29
+ {
30
+ $storeCode = $argv[1];
31
+ }
32
+ else
33
+ {
34
+ // If required, replace Mage_Core_Model_Store::DEFAULT_CODE with your 'storecode'.
35
+ $storeCode = Mage_Core_Model_Store::DEFAULT_CODE;
36
+ }
37
+
38
+ Mage::app('admin')->setUseSessionInUrl(false);
39
+
40
+ $i = 0;
41
+
42
+ foreach (Mage::app()->getWebsites() as $website) {
43
+ foreach ($website->getGroups() as $group) {
44
+ $stores = $group->getStores();
45
+ foreach ($stores as $store) {
46
+ echo $store->getCode() . "\n";
47
+ $feedGenerator = Mage::getModel('feed/generator', array(
48
+ 'cli_mode' => true,
49
+ 'store_code' => $store->getCode(),
50
+ ));
51
+
52
+ $feedGenerator->run();
53
+
54
+ if($i++ > 5)
55
+ {
56
+ sleep(500);
57
+ $i = 0;
58
+ }
59
+ }
60
+ }
61
+ }
62
+
63
+ /*$feedGenerator = Mage::getSingleton('feed/generator', array(
64
+ 'cli_mode' => true,
65
+ 'store_code' => $storeCode,
66
+ ));*/
app/code/community/Sooqr/Feed/scripts/resize_images.php ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once dirname(__FILE__) . '/../../../../../../app/Mage.php';
4
+
5
+ set_time_limit(0);
6
+ /* Setting memory limit depends on the number of products exported.*/
7
+ /*ini_set('memory_limit','600M');*/
8
+ error_reporting(E_ALL);
9
+
10
+ if (!Mage::isInstalled())
11
+ {
12
+ echo 'Application is not installed yet, please complete install wizard first.';
13
+ exit;
14
+ }
15
+
16
+ $_SERVER['SCRIPT_NAME'] = str_replace(basename(__FILE__), 'index.php', $_SERVER['SCRIPT_NAME']);
17
+ $_SERVER['SCRIPT_FILENAME'] = str_replace(basename(__FILE__), 'index.php', $_SERVER['SCRIPT_FILENAME']);
18
+
19
+ Mage::app('admin')->setUseSessionInUrl(false);
20
+
21
+ $feedGenerator = Mage::getSingleton('feed/generator', array(
22
+ 'cli_mode' => true,
23
+ ));
24
+
25
+ $feedGenerator->resizeImages();
app/code/community/Sooqr/Search/Block/Adminhtml/System/Config/Fieldset/Info.php CHANGED
@@ -25,21 +25,23 @@ class Sooqr_Search_Block_Adminhtml_System_Config_Fieldset_Info
25
  $searchEnabled = Mage::getStoreConfig('sooqr/search/enabled');
26
  $accountId = Mage::getStoreConfig('sooqr/accountInformation/accountid');
27
  if ($searchEnabled == 1
28
- && !empty($accountId))
29
- {
30
- $html = '<img style="float: right; margin: 0 0 2em 2em;" src="http://www.sooqr.com/client/sooqr/images/logo_sooqr.png" alt="Sooqr Logo"/>';
31
- $html .= '<p>Have questions or need help? Just contact our <a href="https://support.soort.com/" target="_blank">Sooqr Support-team</a>.</p>';
32
- $html .= '<p>Login with your personal <a href="https://my.sooqr.com/" target="_blank">mySooqr account</a> to change your Sooqr settings and view your usage statistics.</p>';
33
- }
34
- else
35
- {
36
- $html = '<img style="float: right; margin: 0 0 2em 2em;" src="http://www.sooqr.com/client/sooqr/images/logo_sooqr.png" alt="Sooqr Logo"/>';
37
- $html .= '<p>Sooqr is the fastest and most relevant site search for your Magento webshop. We make sure your visitor finds what he is looking for regardless of the number of articles or the amount of content on the site.</p>';
38
- $html .= '<p>To setup your Sooqr, please visit <a href="http://sooqr.com/magento" target="_blank">sooqr.com/magento</a> or check out <a href="http://magento-demo.sooqr.com" target="_blank">our demo</a>.<br/>';
39
- $html .= 'Just start our 30-day-no-creditcard-no-questions-asked-trial today!</p>';
40
- $html .= '<p>Setup is done in 3 easy steps: <a href="http://sooqr.com/magento/signup/" target="_blank">subscribe for your 30-day trial</a>, setup your Sooqr at my.Sooqr.com and enter your account information on this page.<br/>';
41
- $html .= 'Have questions or need help? Just contact our <a href="http://support.sooqr.com/" target="_blank">Sooqr Support-team</a>.</p>';
42
- }
 
 
43
 
44
  return $html;
45
  }
25
  $searchEnabled = Mage::getStoreConfig('sooqr/search/enabled');
26
  $accountId = Mage::getStoreConfig('sooqr/accountInformation/accountid');
27
  if ($searchEnabled == 1
28
+ && !empty($accountId))
29
+ {
30
+ $html = '<div style="max-width: 800px;">';
31
+ $html .= '<img style="float: right; margin: 0 0 2em 2em;" src="http://www.sooqr.com/client/sooqr/images/logo_sooqr_klein.png" alt="Sooqr Logo"/>';
32
+ $html .= '<p><b>Sooqr Search settings</b><br>You are able to add ranking rules, synonyms and get more insights on your Sooqr via our <a href="https://my.sooqr.com" target="_blank">Sooqr Conversion Suite</a>.</p>';
33
+ $html .= '<p>Whenever you have questions or need help with Sooqr Search: feel free to contact our <a href="http://support.sooqr.com" target="_blank">Sooqr Support Team</a>.</p>';
34
+ $html .= '</div>';
35
+ }
36
+ else
37
+ {
38
+ $html = '<div style="max-width: 800px;">';
39
+ $html .= '<img style="float: right; margin: 0 0 2em 2em;" src="http://www.sooqr.com/client/sooqr/images/logo_sooqr_klein.png" alt="Sooqr Logo"/>';
40
+ $html .= '<p><b>Welcome to Sooqr Search!</b><br/>Sooqr is the fastest, most relevant faceted search for your Magento store. Sooqr makes sure your visitors find what they are looking for, regardless of the number of articles you have. In order to start your 30-day trial there are a few things the Sooqr team needs to be doing manually.</p>';
41
+ $html .= '<p>So please go to our <a href="https://www.sooqr.com/sign-up/sooqr-for-magento" target="_blank">signup page</a> and leave your information. We will be happy to provide you with all the information needed. It may take a few days, but we promise: it\'s worth the wait!</p>';
42
+ $html .= '<p>Whenever you have questions or need help with Sooqr Search: feel free to contact our <a href="http://support.sooqr.com" target="_blank">Sooqr Support Team</a>.</p>';
43
+ $html .= '</div>';
44
+ }
45
 
46
  return $html;
47
  }
app/code/community/Sooqr/Search/Block/Form.php CHANGED
@@ -12,6 +12,21 @@ class Sooqr_Search_Block_Form extends Mage_Core_Block_Template
12
  return trim(Mage::getStoreConfig('sooqr/accountInformation/accountid'));
13
  }
14
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  /**
16
  * Returns if the Sooqr Search should be enabled on this site.
17
  *
@@ -23,6 +38,18 @@ class Sooqr_Search_Block_Form extends Mage_Core_Block_Template
23
  && strlen(Mage::getStoreConfig('sooqr/accountInformation/accountid'));
24
  }
25
 
 
 
 
 
 
 
 
 
 
 
 
 
26
  /**
27
  * Returns the language code for Sooqr to use.
28
  *
@@ -54,5 +81,75 @@ class Sooqr_Search_Block_Form extends Mage_Core_Block_Template
54
  {
55
  return 'static.sooqr.com/sooqr.js';
56
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
  }
12
  return trim(Mage::getStoreConfig('sooqr/accountInformation/accountid'));
13
  }
14
 
15
+ /**
16
+ * Returns the current version.
17
+ *
18
+ * @return <integer, NULL> string with account identifier of NULL if not setup
19
+ */
20
+ public function getSooqrVersion()
21
+ {
22
+ $version = Mage::getStoreConfig('sooqr/advanced/frontend_version');
23
+ if (strlen($version))
24
+ {
25
+ return intval($version);
26
+ }
27
+ return null;
28
+ }
29
+
30
  /**
31
  * Returns if the Sooqr Search should be enabled on this site.
32
  *
38
  && strlen(Mage::getStoreConfig('sooqr/accountInformation/accountid'));
39
  }
40
 
41
+ /**
42
+ * Returns if the Sooqr Search statistics tracking is enabled. This can be disabled for staging environments.
43
+ *
44
+ * @return boolean true if enabled, otherwise false
45
+ */
46
+ public function isTrackingEnabled()
47
+ {
48
+ $tracking = Mage::getStoreConfig('sooqr/search/statistics_tracking');
49
+
50
+ return is_null($tracking) || $tracking === '1';
51
+ }
52
+
53
  /**
54
  * Returns the language code for Sooqr to use.
55
  *
81
  {
82
  return 'static.sooqr.com/sooqr.js';
83
  }
84
+ }
85
+
86
+ /**
87
+ * Returns the jQuery selector for the parent under which the results will be added.
88
+ *
89
+ * @return mixed jQuery selector when available, otherwise null
90
+ */
91
+ public function getContainerParent()
92
+ {
93
+ $selector = Mage::getStoreConfig('sooqr/advanced/container_parent');
94
+ if (strlen($selector))
95
+ {
96
+ return $selector;
97
+ }
98
+ return null;
99
+ }
100
+
101
+ /**
102
+ * Returns the jQuery selector for aligning the search results container.
103
+ *
104
+ * @return mixed jQuery selector when available, otherwise null
105
+ */
106
+ public function getAlignToElement()
107
+ {
108
+ $selector = Mage::getStoreConfig('sooqr/advanced/align_to_element');
109
+ if (strlen($selector))
110
+ {
111
+ return $selector;
112
+ }
113
+ return null;
114
+ }
115
+
116
+ /**
117
+ * Returns the requested z-index for the Sooqr overlay
118
+ *
119
+ * @return mixed[int|null] Z-index as integer when defined, otherwise null
120
+ */
121
+ public function getZIndex()
122
+ {
123
+ $zIndex = Mage::getStoreConfig('sooqr/advanced/zindex');
124
+ if (strlen($zIndex))
125
+ {
126
+ return $zIndex;
127
+ }
128
+ return null;
129
  }
130
+
131
+ /**
132
+ * Returns the options for the Sooqr Suggest initialisation.
133
+ *
134
+ * @return array initialisation options
135
+ */
136
+ public function getSooqrOptions()
137
+ {
138
+ $options = array(
139
+ 'account' => $this->getSooqrAccountId(),
140
+ 'fieldId' => 'search',
141
+ );
142
+
143
+ if (!is_null($selector = $this->getContainerParent()))
144
+ {
145
+ $options['containerParent'] = $selector;
146
+ }
147
+ if (!is_null($version = $this->getSooqrVersion())
148
+ && $version != 3)
149
+ {
150
+ $options['version'] = $version;
151
+ }
152
+
153
+ return $options;
154
+ }
155
  }
app/code/community/Sooqr/Search/Model/Accountid.php CHANGED
@@ -14,11 +14,18 @@ class Sooqr_Search_Model_Accountid extends Mage_Core_Model_Config_Data
14
  public function save()
15
  {
16
  $accountId = trim($this->getValue());
17
- if (!preg_match('/^SQ\-[0-9]+\-[0-9]+$/i', $accountId))
 
18
  {
19
  Mage::throwException("Account identifier not in correct format (SQ-999999-1)");
20
  }
21
  $this->setValue($accountId);
 
 
 
 
 
 
22
 
23
  return parent::save();
24
  }
14
  public function save()
15
  {
16
  $accountId = trim($this->getValue());
17
+ if (strlen($accountId)
18
+ && !preg_match('/^SQ\-[0-9]+\-[0-9]+$/i', $accountId))
19
  {
20
  Mage::throwException("Account identifier not in correct format (SQ-999999-1)");
21
  }
22
  $this->setValue($accountId);
23
+
24
+ // Show a warning when API key is empty
25
+ if (strlen($accountId) == 0)
26
+ {
27
+ Mage::getSingleton('adminhtml/session')->addWarning('Please enter the account identifier before activating your Sooqr.');
28
+ }
29
 
30
  return parent::save();
31
  }
app/code/community/Sooqr/Search/Model/Source/Versions.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * NOTICE OF LICENSE
5
+ *
6
+ * This source file is subject to the Open Software License (OSL 3.0)
7
+ * that is bundled with this package in the file LICENSE.txt.
8
+ * It is also available through the world-wide-web at this URL:
9
+ * http://opensource.org/licenses/osl-3.0.php
10
+ *
11
+ * @category Sooqr
12
+ * @package Sooqr_Feed
13
+ * @copyright Copyright (c) 2011 RocketWeb (http://rocketweb.com)
14
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
15
+ * @author RocketWeb
16
+ */
17
+
18
+ class Sooqr_Search_Model_Source_Versions extends Varien_Object
19
+ {
20
+ public function toOptionArray()
21
+ {
22
+ $values = array(
23
+ 3 => 'Version 3 (Original)',
24
+ 4 => 'Version 4 (Responsive)',
25
+ );
26
+
27
+ $options = array();
28
+ foreach ($values as $k => $v)
29
+ {
30
+ $options[] = array('value' => $k, 'label' => $v);
31
+ }
32
+
33
+ return $options;
34
+ }
35
+ }
app/code/community/Sooqr/Search/etc/config.xml CHANGED
@@ -2,7 +2,7 @@
2
  <config>
3
  <modules>
4
  <Sooqr_Search>
5
- <version>1.0.4.4</version>
6
  </Sooqr_Search>
7
  </modules>
8
  <frontend>
@@ -44,9 +44,15 @@
44
  <sooqr>
45
  <search>
46
  <enabled>1</enabled>
 
 
47
  <staging>0</staging>
48
  <debugging>0</debugging>
 
49
  </search>
 
 
 
50
  </sooqr>
51
  </default>
52
  </config>
2
  <config>
3
  <modules>
4
  <Sooqr_Search>
5
+ <version>1.0.5</version>
6
  </Sooqr_Search>
7
  </modules>
8
  <frontend>
44
  <sooqr>
45
  <search>
46
  <enabled>1</enabled>
47
+ <container_parent/>
48
+ <align_to_element/>
49
  <staging>0</staging>
50
  <debugging>0</debugging>
51
+ <statistics_tracking>1</statistics_tracking>
52
  </search>
53
+ <advanced>
54
+ <frontend_version>4</frontend_version>
55
+ </advanced>
56
  </sooqr>
57
  </default>
58
  </config>
app/code/community/Sooqr/Search/etc/system.xml CHANGED
@@ -14,6 +14,7 @@
14
  <sort_order>10</sort_order>
15
  <show_in_default>1</show_in_default>
16
  <show_in_website>1</show_in_website>
 
17
  </info>
18
  <accountInformation translate="label">
19
  <label>Account information</label>
@@ -30,6 +31,7 @@
30
  <sort_order>10</sort_order>
31
  <show_in_default>1</show_in_default>
32
  <show_in_website>1</show_in_website>
 
33
  <backend_model>search/accountid</backend_model>
34
  </accountid>
35
  <apikey translate="label">
@@ -39,6 +41,7 @@
39
  <sort_order>20</sort_order>
40
  <show_in_default>1</show_in_default>
41
  <show_in_website>1</show_in_website>
 
42
  <backend_model>search/apikey</backend_model>
43
  </apikey>
44
  </fields>
@@ -59,7 +62,18 @@
59
  <sort_order>10</sort_order>
60
  <show_in_default>1</show_in_default>
61
  <show_in_website>1</show_in_website>
 
62
  </enabled>
 
 
 
 
 
 
 
 
 
 
63
  </fields>
64
  </search>
65
  <advanced translate="label">
@@ -67,25 +81,65 @@
67
  <sort_order>200</sort_order>
68
  <show_in_default>1</show_in_default>
69
  <show_in_website>1</show_in_website>
 
70
  <fields>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
  <staging translate="label">
72
  <label>Staging environment</label>
73
- <comment><![CDATA[ Only for testing purposes ]]></comment>
74
  <frontend_type>select</frontend_type>
75
  <source_model>adminhtml/system_config_source_yesno</source_model>
76
- <sort_order>10</sort_order>
77
  <show_in_default>1</show_in_default>
78
  <show_in_website>1</show_in_website>
 
79
  </staging>
80
  <debugging translate="label">
81
  <label>Enable debugging</label>
82
- <comment><![CDATA[ Show error messages in the browser ]]></comment>
83
  <frontend_type>select</frontend_type>
84
  <source_model>adminhtml/system_config_source_yesno</source_model>
85
- <sort_order>20</sort_order>
86
  <show_in_default>1</show_in_default>
87
  <show_in_website>1</show_in_website>
 
88
  </debugging>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
  </fields>
90
  </advanced>
91
  </groups>
14
  <sort_order>10</sort_order>
15
  <show_in_default>1</show_in_default>
16
  <show_in_website>1</show_in_website>
17
+ <show_in_store>1</show_in_store>
18
  </info>
19
  <accountInformation translate="label">
20
  <label>Account information</label>
31
  <sort_order>10</sort_order>
32
  <show_in_default>1</show_in_default>
33
  <show_in_website>1</show_in_website>
34
+ <show_in_store>1</show_in_store>
35
  <backend_model>search/accountid</backend_model>
36
  </accountid>
37
  <apikey translate="label">
41
  <sort_order>20</sort_order>
42
  <show_in_default>1</show_in_default>
43
  <show_in_website>1</show_in_website>
44
+ <show_in_store>1</show_in_store>
45
  <backend_model>search/apikey</backend_model>
46
  </apikey>
47
  </fields>
62
  <sort_order>10</sort_order>
63
  <show_in_default>1</show_in_default>
64
  <show_in_website>1</show_in_website>
65
+ <show_in_store>1</show_in_store>
66
  </enabled>
67
+ <statistics_tracking translate="label">
68
+ <label>Enable statistics tracking</label>
69
+ <comment><![CDATA[ Disable the statistics tracking for your staging environment. When disabled, we cannot show statistics in mySooqr. ]]></comment>
70
+ <frontend_type>select</frontend_type>
71
+ <source_model>adminhtml/system_config_source_yesno</source_model>
72
+ <sort_order>20</sort_order>
73
+ <show_in_default>1</show_in_default>
74
+ <show_in_website>1</show_in_website>
75
+ <show_in_store>1</show_in_store>
76
+ </statistics_tracking>
77
  </fields>
78
  </search>
79
  <advanced translate="label">
81
  <sort_order>200</sort_order>
82
  <show_in_default>1</show_in_default>
83
  <show_in_website>1</show_in_website>
84
+ <show_in_store>1</show_in_store>
85
  <fields>
86
+ <container_parent translate="label">
87
+ <label>Parent HTML node for container</label>
88
+ <comment><![CDATA[ Empty by default. Defines the parent node for the Sooqr result container. Can contain any jQuery selector. ]]></comment>
89
+ <frontend_type>text</frontend_type>
90
+ <sort_order>10</sort_order>
91
+ <show_in_default>1</show_in_default>
92
+ <show_in_website>1</show_in_website>
93
+ <show_in_store>1</show_in_store>
94
+ </container_parent>
95
+ <align_to_element translate="label">
96
+ <label>Align to HTML element</label>
97
+ <comment><![CDATA[ Empty by default. Defines the node to align the search results with. Can contain any jQuery selector. ]]></comment>
98
+ <frontend_type>text</frontend_type>
99
+ <sort_order>20</sort_order>
100
+ <show_in_default>1</show_in_default>
101
+ <show_in_website>1</show_in_website>
102
+ <show_in_store>1</show_in_store>
103
+ </align_to_element>
104
  <staging translate="label">
105
  <label>Staging environment</label>
106
+ <comment><![CDATA[ Do not enable unless requested by Sooqr support. Connect with Sooqr Staging environment. ]]></comment>
107
  <frontend_type>select</frontend_type>
108
  <source_model>adminhtml/system_config_source_yesno</source_model>
109
+ <sort_order>30</sort_order>
110
  <show_in_default>1</show_in_default>
111
  <show_in_website>1</show_in_website>
112
+ <show_in_store>1</show_in_store>
113
  </staging>
114
  <debugging translate="label">
115
  <label>Enable debugging</label>
116
+ <comment><![CDATA[ Do not enable unless requested by Sooqr support. Show error messages in the browser. ]]></comment>
117
  <frontend_type>select</frontend_type>
118
  <source_model>adminhtml/system_config_source_yesno</source_model>
119
+ <sort_order>40</sort_order>
120
  <show_in_default>1</show_in_default>
121
  <show_in_website>1</show_in_website>
122
+ <show_in_store>1</show_in_store>
123
  </debugging>
124
+ <frontend_version translate="label">
125
+ <label>Frontend version</label>
126
+ <comment><![CDATA[ Specifies the Sooqr version to use. Defaults to 4 for new accounts. Do not change unless requested by Sooqr support. ]]></comment>
127
+ <frontend_type>select</frontend_type>
128
+ <source_model>search/source_versions</source_model>
129
+ <sort_order>50</sort_order>
130
+ <show_in_default>1</show_in_default>
131
+ <show_in_website>1</show_in_website>
132
+ <show_in_store>1</show_in_store>
133
+ </frontend_version>
134
+ <zindex translate="label">
135
+ <label>Overlay CSS z-index</label>
136
+ <comment><![CDATA[ Overrules the default z-index for the Sooqr overlay. ]]></comment>
137
+ <frontend_type>text</frontend_type>
138
+ <sort_order>60</sort_order>
139
+ <show_in_default>1</show_in_default>
140
+ <show_in_website>1</show_in_website>
141
+ <show_in_store>1</show_in_store>
142
+ </zindex>
143
  </fields>
144
  </advanced>
145
  </groups>
app/design/frontend/default/default/template/catalogsearch/form.mini.phtml CHANGED
@@ -1,27 +1,35 @@
1
  <form id="search_mini_form" action="<?php echo $this->helper('catalogsearch')->getResultUrl() ?>" method="get">
2
  <div class="form-search">
3
  <label for="search"><?php echo $this->__('Search:') ?></label>
4
- <input id="search" type="text" name="<?php echo $this->helper('catalogsearch')->getQueryParamName() ?>" value="<?php echo $this->helper('catalogsearch')->getEscapedQueryText() ?>" class="input-text" />
5
  <button type="submit" title="<?php echo $this->__('Search') ?>" class="button"><span><span><?php echo $this->__('Search') ?></span></span></button>
6
 
7
  <?php if ($this->isEnabled()) : ?>
8
 
 
9
  <script type="text/javascript">
10
-
11
- var _wssq = _wssq || [];
12
- _wssq.push(['_load', { 'suggest' : { 'account' : '<?php echo $this->getSooqrAccountId() ?>', 'fieldId' : 'search'}}]);
13
- _wssq.push(['suggest._setPosition', 'screen-middle']);
14
- _wssq.push(['suggest._setFixedFilters', { 'magento_store' : '<?php echo Mage::app()->getStore()->getCode(); ?>' }]);
15
- _wssq.push(['suggest._setLocale', '<?php echo $this->getSooqrLanguage() ?>']);
16
-
17
- (function() {
18
- var ws = document.createElement('script'); ws.type = 'text/javascript'; ws.async = true;
19
- ws.src = ('https:' == document.location.protocol ? 'https://' : 'http://') + '<?php echo $this->getSooqrScriptUri() ?>';
20
- var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ws, s);
21
- })();
22
-
 
 
 
 
 
 
23
  </script>
 
24
 
25
  <?php endif; ?>
26
  </div>
27
- </form>
1
  <form id="search_mini_form" action="<?php echo $this->helper('catalogsearch')->getResultUrl() ?>" method="get">
2
  <div class="form-search">
3
  <label for="search"><?php echo $this->__('Search:') ?></label>
4
+ <input onfocus="if(this.value == 'Zoekopdracht invoeren')this.value = '';" onblur="if(this.value == '')this.value = 'Zoekopdracht invoeren';" id="search" type="text" name="<?php echo $this->helper('catalogsearch')->getQueryParamName() ?>" value="<?php echo $this->helper('catalogsearch')->getEscapedQueryText() ? $this->helper('catalogsearch')->getEscapedQueryText() : 'Zoekopdracht invoeren'; ?>" class="input-text" />
5
  <button type="submit" title="<?php echo $this->__('Search') ?>" class="button"><span><span><?php echo $this->__('Search') ?></span></span></button>
6
 
7
  <?php if ($this->isEnabled()) : ?>
8
 
9
+ <!-- Start Sooqr.com on-site search and navigation code -->
10
  <script type="text/javascript">
11
+ var _wssq = _wssq || [];
12
+ var setResizeSooqrFunction= false;
13
+
14
+ _wssq.push(['_load', { 'suggest' : { 'account' : 'SQ-100491-1', 'version':4, fieldId : 'search'}}]); // Plaats hier de account code en het id van het zoek veld
15
+ //_wssq.push(['suggest._setPosition', 'element-relative', 'div.col-main']);
16
+ _wssq.push(['suggest._setPosition', 'screen-middle', {top:76}]);
17
+ _wssq.push(['suggest._setLocale', 'nl_NL']);
18
+ _wssq.push(['suggest._excludePlaceholders', ['Zoekopdracht invoeren']]); // Plaats hier je placeholder zodat deze Sooqr niet activeert in sommige browsers
19
+ _wssq.push(['suggest._setFixedFilters', { 'magento_store' : 'hm_electronic_black' }]);
20
+
21
+ _wssq.push(['suggest._bindEvent', 'open', function(){
22
+ if(!setResizeSooqrFunction) {$jQ( window ).resize(function() {if($jQ('.sooqrSearchContainer-100491-1').is(':visible')) {websight.sooqr.instances['SQ-100491-1'].positionContainer(null, null, true);}});setResizeSooqrFunction = true;}
23
+ }]);
24
+
25
+ (function() {
26
+ var ws = document.createElement('script'); ws.type = 'text/javascript'; ws.async = true;
27
+ ws.src = ('https:' == document.location.protocol ? 'https://' : 'http://') + 'static.sooqr.com/sooqr.js';
28
+ var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ws, s);
29
+ })();
30
  </script>
31
+ <!-- End Sooqr.com on-site search and navigation code -->
32
 
33
  <?php endif; ?>
34
  </div>
35
+ </form>
app/etc/modules/Sooqr_All.xml CHANGED
@@ -13,4 +13,29 @@
13
  </depends>
14
  </Sooqr_Search>
15
  </modules>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  </config>
13
  </depends>
14
  </Sooqr_Search>
15
  </modules>
16
+ <global>
17
+ <events>
18
+ <clean_catalog_images_cache_after>
19
+ <observers>
20
+ <Sooqr_Feed>
21
+ <type>model</type>
22
+ <class>Sooqr_Feed_Model_Generator</class>
23
+ <method>setRecreateImages</method>
24
+ </Sooqr_Feed>
25
+ </observers>
26
+ </clean_catalog_images_cache_after>
27
+ </events>
28
+ </global>
29
+ <crontab>
30
+ <jobs>
31
+ <check_recreate_images>
32
+ <schedule>
33
+ <cron_expr>* * * * *</cron_expr>
34
+ </schedule>
35
+ <run>
36
+ <model>feed/generator::checkRecreateImages</model>
37
+ </run>
38
+ </check_recreate_images>
39
+ </jobs>
40
+ </crontab>
41
  </config>
package.xml CHANGED
@@ -1,18 +1,36 @@
1
  <?xml version="1.0"?>
2
  <package>
3
  <name>SooqrSearch</name>
4
- <version>1.0.4.4</version>
5
  <stability>stable</stability>
6
  <license uri="http://www.opensource.org/licenses/osl-3.0.php">OSL v3.0</license>
7
  <channel>community</channel>
8
  <extends/>
9
  <summary>Extension to link your Magento shop to the Sooqr.com onSite Search sollution.</summary>
10
  <description>Provides an interface to implement the Sooqr onSite Search from sooqr.com. Sooqr.com is a paid service that enabled fast searches in your webshop for a monthly fee.</description>
11
- <notes>Changes since 1.0.4.3&#xD;
12
- - Better support for multiselect attributefields.&#xD;
 
13
  &#xD;
14
  Changes since 1.0.4&#xD;
15
- - Better support for additional product types.&#xD;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  &#xD;
17
  Changes since 1.0.3.1&#xD;
18
  - Plugin now reports basic configuration settings to the mySooqr backend.&#xD;
@@ -60,9 +78,9 @@ Changes since 0.3.2&#xD;
60
  - Bugfix: manufacterer field is not always available&#xD;
61
  - Changes to the visibility of configuration fields</notes>
62
  <authors><author><name>internetbureau Websight</name><user>MAG001537415</user><email>info@websight.nl</email></author></authors>
63
- <date>2013-04-08</date>
64
- <time>08:44:36</time>
65
- <contents><target name="magecommunity"><dir name="Sooqr"><dir name="Feed"><dir name="Block"><dir name="Adminhtml"><dir name="System"><dir name="Config"><dir name="Form"><dir name="Field"><file name="Customfieldmap.php" hash="d97b98a3d7124a79cc392b28ce2a1cfe"/><file name="Fieldmap.php" hash="dd8c9702387d90f299b6a5455d325433"/></dir></dir></dir></dir></dir></dir><dir name="Helper"><file name="Data.php" hash="0532014143c11589f849f518268666ad"/><file name="SimpleXml.php" hash="d1a96945172013ac9300c2d49ed02272"/><file name="Tax.php" hash="ced1a074e7e104ada5b925bd64feac1d"/></dir><dir name="Model"><file name="Batch.php" hash="a855b80d9f52a39f672433f338730e77"/><file name="Config.php" hash="e4f4913671b94b0cfc544e020a625e0a"/><file name="Generator.php" hash="fd1af7250796badb568feb86da421b66"/><dir name="Map"><dir name="Product"><file name="Abstract.php" hash="3a4e4780af924afaafc953805def3ac7"/><file name="Associated.php" hash="2d283bccff7d6877af3821a46e7eb45e"/><file name="Bundle.php" hash="b60c6693ee23f46ef8a50dbb1d9b8d0f"/><file name="Configurable.php" hash="3de638ac19855a7cbb22f9f081cdff37"/><file name="Downloadable.php" hash="9b27773f6ff9a1b3735ecbbdab81dfef"/><file name="Grouped.php" hash="2f601ee768bdbe52aa2cf132ec7f43f8"/><file name="Simple.php" hash="f03e7d90056b504d55421c830de832f6"/><file name="Virtual.php" hash="e4dc62af4843bcb04910f8e9643f2707"/></dir></dir><dir name="Source"><file name="Producttypes.php" hash="ab9ccbf7457485bbfa659a0315b8459b"/></dir><dir name="System"><dir name="Config"><dir name="Backend"><dir name="Serialized"><file name="Customfieldmap.php" hash="6dbe62d8c85410adcc3e70cf022fed2e"/><file name="Fieldmap.php" hash="d1f135a74f9a8525b173ef083c2f86e5"/></dir></dir><file name="Minmax.php" hash="f8d72832fd7bab8c0ebd7771271e4566"/></dir></dir><file name="Tools.php" hash="79e0621c9ed2f8713332a976f5580a5a"/></dir><dir name="controllers"><file name="IndexController.php" hash="1e5dfb6b6ca7669474b8ebc997556e61"/><file name="InstallationController.php" hash="14af7b0f8de13e7b750cbe3a4d2afc53"/></dir><dir name="etc"><file name="adminhtml.xml" hash="caee7117f32a2d2876d8dc1ecb65b242"/><file name="config.xml" hash="f0e24acc985d87c39085f15717519b6e"/><file name="system.xml" hash="512e026374bb7326c907a47a61031935"/></dir><dir name="scripts"><file name="generate_sooqr_feed.php" hash="ed419d31d0a99b31411fef1c97e54e20"/></dir></dir><dir name="Search"><dir name="Block"><dir name="Adminhtml"><dir name="System"><dir name="Config"><dir name="Fieldset"><file name="Info.php" hash="ba0e6b2b6e89c74df1307402f1cb06a9"/><file name="Subscription.php" hash="d7e2f80aefca37ffa529ca0cc0e6628b"/></dir></dir></dir></dir><file name="Form.php" hash="1fa0ccfc5d74f73ff1f83343ef4eac38"/></dir><dir name="Helper"><file name="Data.php" hash="56efae35a7098b6fd3e5320978ca4033"/></dir><dir name="Model"><file name="Accountid.php" hash="dbcdf5cc551f290f2956d3f7d4cce80e"/><file name="Apikey.php" hash="ac8dff7af6eccbfd02377b9646141724"/></dir><dir name="controllers"><file name="IndexController.php" hash="5312ccf85d0a100b7012e1b09ba3c154"/></dir><dir name="etc"><file name="adminhtml.xml" hash="a78e427e0f53e805fb006add7d97a1de"/><file name="config.xml" hash="ea298c1d7252b5ede4eefdba0333a03b"/><file name="system.xml" hash="d023a96a29ac009bb534d03ed6c170d2"/></dir></dir></dir></target><target name="magedesign"><dir name="frontend"><dir name="default"><dir name="default"><dir name="template"><dir name="catalogsearch"><file name="form.mini.phtml" hash="1b873015cd5f53c265918321ad282d29"/></dir></dir><dir name="layout"><file name="sooqr_catalogsearch.xml" hash="72678b32666d8e337a84628272f9d32f"/></dir></dir></dir></dir><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="template"><dir name="sooqr"><dir name="system"><dir name="config"><dir name="form"><dir name="field"><file name="array.phtml" hash="7ffbc4fe410e27973225df4d660c21a6"/><file name="customarray.phtml" hash="a228172a2d611c8825a721d81db03610"/></dir></dir></dir></dir></dir></dir></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="Sooqr_All.xml" hash="d11d8aab88e28336bae51c325d043a59"/></dir></target></contents>
66
  <compatible/>
67
- <dependencies><required><php><min>5.2.6</min><max>6.0.0</max></php><extension><name>dom</name><min></min><max></max></extension><extension><name>SimpleXML</name><min></min><max></max></extension><extension><name>curl</name><min></min><max></max></extension></required></dependencies>
68
  </package>
1
  <?xml version="1.0"?>
2
  <package>
3
  <name>SooqrSearch</name>
4
+ <version>1.0.5</version>
5
  <stability>stable</stability>
6
  <license uri="http://www.opensource.org/licenses/osl-3.0.php">OSL v3.0</license>
7
  <channel>community</channel>
8
  <extends/>
9
  <summary>Extension to link your Magento shop to the Sooqr.com onSite Search sollution.</summary>
10
  <description>Provides an interface to implement the Sooqr onSite Search from sooqr.com. Sooqr.com is a paid service that enabled fast searches in your webshop for a monthly fee.</description>
11
+ <notes>Incompatible changes since 1.0.4:&#xD;
12
+ - Customers with custom changes to their plugin should NOT update to this new version. Please contact Sooqr support for more information.&#xD;
13
+ - The Sooqr plugin now defaults to the new responsive design. This only works if your account has been upgraded to the responsive templates. Please change the setting 'Frontend version' under 'Advanced settings' to 'Version 3 (Original)'.&#xD;
14
  &#xD;
15
  Changes since 1.0.4&#xD;
16
+ - Support for catalog price rules.&#xD;
17
+ - Better support for custom product types.&#xD;
18
+ - Bugfixes for promotional prices.&#xD;
19
+ - Extra options to align Sooqr to base design.&#xD;
20
+ - Bugfix for selecting the correct store ID.&#xD;
21
+ - Products from inactive categories are now excluded.&#xD;
22
+ - Added basic logging.&#xD;
23
+ - Possibility to start the generator from another Mage event.&#xD;
24
+ - Setting for custom thumbnail size.&#xD;
25
+ - Enable/disable categories in Sooqr feed.&#xD;
26
+ - Bufixes for products with special chars.&#xD;
27
+ - Thumbnail are now recreated on the background after the cache is cleared.&#xD;
28
+ - Keywords are now also exported&#xD;
29
+ - The SKU's for grouped products are now exported as a single string&#xD;
30
+ - Stock info is now exported&#xD;
31
+ - Product type is now exported&#xD;
32
+ - Bugfix grouped priceses&#xD;
33
+ &#xD;
34
  &#xD;
35
  Changes since 1.0.3.1&#xD;
36
  - Plugin now reports basic configuration settings to the mySooqr backend.&#xD;
78
  - Bugfix: manufacterer field is not always available&#xD;
79
  - Changes to the visibility of configuration fields</notes>
80
  <authors><author><name>internetbureau Websight</name><user>MAG001537415</user><email>info@websight.nl</email></author></authors>
81
+ <date>2014-12-01</date>
82
+ <time>16:43:09</time>
83
+ <contents><target name="magecommunity"><dir name="Sooqr"><dir name="Feed"><dir name="Block"><dir name="Adminhtml"><dir name="System"><dir name="Config"><dir name="Form"><dir name="Field"><file name="Customfieldmap.php" hash="24f561edf9e710dad754a7f0777d8350"/><file name="Fieldmap.php" hash="a92c4ca06d1167553731a6e70344398b"/></dir></dir></dir></dir></dir></dir><dir name="Helper"><file name="Data.php" hash="0532014143c11589f849f518268666ad"/><file name="SimpleXml.php" hash="45e6190eb1b5460b02a8eccd2461231d"/><file name="Tax.php" hash="071ffef0b030ee9f1ee4a2ddd012ddfc"/></dir><dir name="Model"><file name="Batch.php" hash="a855b80d9f52a39f672433f338730e77"/><file name="Config.php" hash="75013c6ebe272033bff6500cc4c0b8ba"/><file name="Generator.php" hash="1338f1fd706d3f535721acc4a222d0ba"/><dir name="Map"><dir name="Page"><file name="Abstract.php" hash="9bdd8c460f90bd0ba4c9aac3b7f5ed3e"/></dir><dir name="Product"><file name="Abstract.php" hash="55f738f942cdad7b6a8cf6b7305a477f"/><file name="Associated.php" hash="64e308eda08e0c898ffe573b6bf5a1d8"/><file name="Bundle.php" hash="61978a5fac4af9c9c57ff7a2c10a664a"/><file name="Configurable.php" hash="936d2248f078b1460088d95f9493848b"/><file name="Downloadable.php" hash="9b27773f6ff9a1b3735ecbbdab81dfef"/><file name="Grouped.php" hash="816b4b0d2833380686f6551e0d91c4d2"/><file name="Simple.php" hash="f03e7d90056b504d55421c830de832f6"/><file name="Virtual.php" hash="e4dc62af4843bcb04910f8e9643f2707"/></dir></dir><dir name="Source"><file name="Producttypes.php" hash="26ab333aa4e70a824b439da9f6ef9da6"/></dir><dir name="System"><dir name="Config"><dir name="Backend"><dir name="Serialized"><file name="Customfieldmap.php" hash="e4e383e17c47e6d4a713f832ebd6ba34"/><file name="Fieldmap.php" hash="17064d19ebc4bafd51032aedd41a9bb5"/></dir></dir><file name="Minmax.php" hash="f8d72832fd7bab8c0ebd7771271e4566"/></dir></dir><file name="Tools.php" hash="e66ab5948930360c86a825792e93e463"/></dir><dir name="controllers"><file name="IndexController.php" hash="2ee1d345fe5965663c499fb0cec74805"/><file name="InstallationController.php" hash="14af7b0f8de13e7b750cbe3a4d2afc53"/></dir><dir name="etc"><file name="adminhtml.xml" hash="caee7117f32a2d2876d8dc1ecb65b242"/><file name="config.xml" hash="7d834ab4953ff3fdf7f5963fba9dbfa1"/><file name="system.xml" hash="cf1a4b17598dab16f7e9ca6a49440bd8"/></dir><dir name="scripts"><file name="generate_sooqr_feed.php" hash="f39d450b4c6261f199f015a88c8dab87"/><file name="generate_sooqr_feed2.php" hash="dfdfa827757da3ad1fd7178e7475245b"/><file name="resize_images.php" hash="b42748c2cd8cf60ccb3d7b5029d33381"/></dir></dir><dir name="Search"><dir name="Block"><dir name="Adminhtml"><dir name="System"><dir name="Config"><dir name="Fieldset"><file name="Info.php" hash="1d289328ccfa2f41421fee41c24d0fdd"/><file name="Subscription.php" hash="d7e2f80aefca37ffa529ca0cc0e6628b"/></dir></dir></dir></dir><file name="Form.php" hash="b4734597dbd4acc5e215e3de8e8d3a80"/></dir><dir name="Helper"><file name="Data.php" hash="56efae35a7098b6fd3e5320978ca4033"/></dir><dir name="Model"><file name="Accountid.php" hash="8a8d008b36f95d581184e08443d86a02"/><file name="Apikey.php" hash="ac8dff7af6eccbfd02377b9646141724"/><dir name="Source"><file name="Versions.php" hash="0e0eb4eaf681c9727f94c7192459fa89"/></dir></dir><dir name="controllers"><file name="IndexController.php" hash="5312ccf85d0a100b7012e1b09ba3c154"/></dir><dir name="etc"><file name="adminhtml.xml" hash="a78e427e0f53e805fb006add7d97a1de"/><file name="config.xml" hash="53512abe33475fdedb0f09555cc1e102"/><file name="system.xml" hash="5cf0b0e228ab78f4aff5fdaf0b496163"/></dir></dir></dir></target><target name="magedesign"><dir name="frontend"><dir name="default"><dir name="default"><dir name="template"><dir name="catalogsearch"><file name="form.mini.phtml" hash="5bc2b4f29830fab2a7aa43d8cf9d4880"/></dir></dir><dir name="layout"><file name="sooqr_catalogsearch.xml" hash="72678b32666d8e337a84628272f9d32f"/></dir></dir></dir></dir><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="template"><dir name="sooqr"><dir name="system"><dir name="config"><dir name="form"><dir name="field"><file name="array.phtml" hash="7ffbc4fe410e27973225df4d660c21a6"/><file name="customarray.phtml" hash="a228172a2d611c8825a721d81db03610"/></dir></dir></dir></dir></dir></dir></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="Sooqr_All.xml" hash="c298fd1f525fbfd798e374595af1c9b5"/></dir></target></contents>
84
  <compatible/>
85
+ <dependencies><required><php><min>5.2.6</min><max>6.0.0</max></php><extension><name>dom</name><min/><max/></extension><extension><name>SimpleXML</name><min/><max/></extension><extension><name>curl</name><min/><max/></extension></required></dependencies>
86
  </package>