1: <?php
2: /**
3: * Magento
4: *
5: * NOTICE OF LICENSE
6: *
7: * This source file is subject to the Open Software License (OSL 3.0)
8: * that is bundled with this package in the file LICENSE.txt.
9: * It is also available through the world-wide-web at this URL:
10: * http://opensource.org/licenses/osl-3.0.php
11: * If you did not receive a copy of the license and are unable to
12: * obtain it through the world-wide-web, please send an email
13: * to license@magentocommerce.com so we can send you a copy immediately.
14: *
15: * DISCLAIMER
16: *
17: * Do not edit or add to this file if you wish to upgrade Magento to newer
18: * versions in the future. If you wish to customize Magento for your
19: * needs please refer to http://www.magentocommerce.com for more information.
20: *
21: * @category Mage
22: * @package Mage_ImportExport
23: * @copyright Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
24: * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25: */
26:
27: /**
28: * Import entity abstract product type model
29: *
30: * @category Mage
31: * @package Mage_ImportExport
32: * @author Magento Core Team <core@magentocommerce.com>
33: */
34: abstract class Mage_ImportExport_Model_Import_Entity_Product_Type_Abstract
35: {
36: /**
37: * Product type attribute sets and attributes parameters.
38: *
39: * [attr_set_name_1] => array(
40: * [attr_code_1] => array(
41: * 'options' => array(),
42: * 'type' => 'text', 'price', 'textarea', 'select', etc.
43: * 'id' => ..
44: * ),
45: * ...
46: * ),
47: * ...
48: *
49: * @var array
50: */
51: protected $_attributes = array();
52:
53: /**
54: * Attributes' codes which will be allowed anyway, independently from its visibility property.
55: *
56: * @var array
57: */
58: protected $_forcedAttributesCodes = array();
59:
60: /**
61: * Attributes with index (not label) value.
62: *
63: * @var array
64: */
65: protected $_indexValueAttributes = array();
66:
67: /**
68: * Validation failure message template definitions
69: *
70: * @var array
71: */
72: protected $_messageTemplates = array();
73:
74: /**
75: * Column names that holds values with particular meaning.
76: *
77: * @var array
78: */
79: protected $_particularAttributes = array();
80:
81: /**
82: * Product entity object.
83: *
84: * @var Mage_ImportExport_Model_Import_Entity_Product
85: */
86: protected $_entityModel;
87:
88: /**
89: * Product type (simple, configurable, etc.).
90: *
91: * @var string
92: */
93: protected $_type;
94:
95: /**
96: * Object constructor.
97: *
98: * @param array $params
99: * @param string $type Product type (simple, configurable, etc.)
100: * @throws Exception
101: * @return void
102: */
103: final public function __construct(array $params)
104: {
105: if ($this->isSuitable()) {
106: if (!isset($params[0]) || !isset($params[1])
107: || !is_object($params[0]) || !($params[0] instanceof Mage_ImportExport_Model_Import_Entity_Product)) {
108: Mage::throwException(Mage::helper('importexport')->__('Invalid parameters'));
109: }
110: $this->_entityModel = $params[0];
111: $this->_type = $params[1];
112:
113: foreach ($this->_messageTemplates as $errorCode => $message) {
114: $this->_entityModel->addMessageTemplate($errorCode, $message);
115: }
116: $this->_initAttributes();
117: }
118: }
119:
120: /**
121: * Add attribute parameters to appropriate attribute set.
122: *
123: * @param string $attrSetName Name of attribute set.
124: * @param array $attrParams Refined attribute parameters.
125: * @return Mage_ImportExport_Model_Import_Entity_Product_Type_Abstract
126: */
127: protected function _addAttributeParams($attrSetName, array $attrParams)
128: {
129: if (!$attrParams['apply_to'] || in_array($this->_type, $attrParams['apply_to'])) {
130: $this->_attributes[$attrSetName][$attrParams['code']] = $attrParams;
131: }
132: return $this;
133: }
134:
135: /**
136: * Return product attributes for its attribute set specified in row data.
137: *
138: * @param array|string $attrSetData Product row data or simply attribute set name.
139: * @return array
140: */
141: protected function _getProductAttributes($attrSetData)
142: {
143: if (is_array($attrSetData)) {
144: return $this->_attributes[$attrSetData[Mage_ImportExport_Model_Import_Entity_Product::COL_ATTR_SET]];
145: } else {
146: return $this->_attributes[$attrSetData];
147: }
148: }
149:
150: /**
151: * Initialize attributes parameters for all attributes' sets.
152: *
153: * @return Mage_ImportExport_Model_Import_Entity_Product_Type_Abstract
154: */
155: protected function _initAttributes()
156: {
157: // temporary storage for attributes' parameters to avoid double querying inside the loop
158: $attributesCache = array();
159:
160: foreach (Mage::getResourceModel('eav/entity_attribute_set_collection')
161: ->setEntityTypeFilter($this->_entityModel->getEntityTypeId()) as $attributeSet) {
162: foreach (Mage::getResourceModel('catalog/product_attribute_collection')
163: ->setAttributeSetFilter($attributeSet->getId()) as $attribute) {
164:
165: $attributeCode = $attribute->getAttributeCode();
166: $attributeId = $attribute->getId();
167:
168: if ($attribute->getIsVisible() || in_array($attributeCode, $this->_forcedAttributesCodes)) {
169: if (!isset($attributesCache[$attributeId])) {
170: $attributesCache[$attributeId] = array(
171: 'id' => $attributeId,
172: 'code' => $attributeCode,
173: 'for_configurable' => $attribute->getIsConfigurable(),
174: 'is_global' => $attribute->getIsGlobal(),
175: 'is_required' => $attribute->getIsRequired(),
176: 'is_unique' => $attribute->getIsUnique(),
177: 'frontend_label' => $attribute->getFrontendLabel(),
178: 'is_static' => $attribute->isStatic(),
179: 'apply_to' => $attribute->getApplyTo(),
180: 'type' => Mage_ImportExport_Model_Import::getAttributeType($attribute),
181: 'default_value' => strlen($attribute->getDefaultValue())
182: ? $attribute->getDefaultValue() : null,
183: 'options' => $this->_entityModel
184: ->getAttributeOptions($attribute, $this->_indexValueAttributes)
185: );
186: }
187: $this->_addAttributeParams($attributeSet->getAttributeSetName(), $attributesCache[$attributeId]);
188: }
189: }
190: }
191: return $this;
192: }
193:
194: /**
195: * Have we check attribute for is_required? Used as last chance to disable this type of check.
196: *
197: * @param string $attrCode
198: * @return bool
199: */
200: protected function _isAttributeRequiredCheckNeeded($attrCode)
201: {
202: return true;
203: }
204:
205: /**
206: * Validate particular attributes columns.
207: *
208: * @param array $rowData
209: * @param int $rowNum
210: * @return bool
211: */
212: protected function _isParticularAttributesValid(array $rowData, $rowNum)
213: {
214: return true;
215: }
216:
217: /**
218: * Check price correction value validity (signed integer or float with or without percentage sign).
219: *
220: * @param string $value
221: * @return int
222: */
223: protected function _isPriceCorr($value)
224: {
225: return preg_match('/^-?\d+\.?\d*%?$/', $value);
226: }
227:
228: /**
229: * Particular attribute names getter.
230: *
231: * @return array
232: */
233: public function getParticularAttributes()
234: {
235: return $this->_particularAttributes;
236: }
237:
238: /**
239: * Validate row attributes. Pass VALID row data ONLY as argument.
240: *
241: * @param array $rowData
242: * @param int $rowNum
243: * @param boolean $checkRequiredAttributes OPTIONAL Flag which can disable validation required values.
244: * @return boolean
245: */
246: public function isRowValid(array $rowData, $rowNum, $checkRequiredAttributes = true)
247: {
248: $error = false;
249: $rowScope = $this->_entityModel->getRowScope($rowData);
250:
251: if (Mage_ImportExport_Model_Import_Entity_Product::SCOPE_NULL != $rowScope) {
252: foreach ($this->_getProductAttributes($rowData) as $attrCode => $attrParams) {
253: // check value for non-empty in the case of required attribute?
254: if (isset($rowData[$attrCode]) && strlen($rowData[$attrCode])) {
255: $error |= !$this->_entityModel->isAttributeValid($attrCode, $attrParams, $rowData, $rowNum);
256: } elseif (
257: $this->_isAttributeRequiredCheckNeeded($attrCode)
258: && $checkRequiredAttributes
259: && Mage_ImportExport_Model_Import_Entity_Product::SCOPE_DEFAULT == $rowScope
260: && $attrParams['is_required']
261: ) {
262: $this->_entityModel->addRowError(
263: Mage_ImportExport_Model_Import_Entity_Product::ERROR_VALUE_IS_REQUIRED, $rowNum, $attrCode
264: );
265: $error = true;
266: }
267: }
268: }
269: $error |= !$this->_isParticularAttributesValid($rowData, $rowNum);
270:
271: return !$error;
272: }
273:
274: /**
275: * Additional check for model availability. If method returns FALSE - model is not suitable for data processing.
276: *
277: * @return bool
278: */
279: public function isSuitable()
280: {
281: return true;
282: }
283:
284: /**
285: * Prepare attributes values for save: remove non-existent, remove empty values, remove static.
286: *
287: * @param array $rowData
288: * @return array
289: */
290: public function prepareAttributesForSave(array $rowData)
291: {
292: $resultAttrs = array();
293:
294: foreach ($this->_getProductAttributes($rowData) as $attrCode => $attrParams) {
295: if (!$attrParams['is_static']) {
296: if (isset($rowData[$attrCode]) && strlen($rowData[$attrCode])) {
297: $resultAttrs[$attrCode] =
298: ('select' == $attrParams['type'] || 'multiselect' == $attrParams['type'])
299: ? $attrParams['options'][strtolower($rowData[$attrCode])]
300: : $rowData[$attrCode];
301: } elseif (array_key_exists($attrCode, $rowData)) {
302: $resultAttrs[$attrCode] = $rowData[$attrCode];
303: } elseif (null !== $attrParams['default_value']) {
304: $resultAttrs[$attrCode] = $attrParams['default_value'];
305: }
306: }
307: }
308: return $resultAttrs;
309: }
310:
311: /**
312: * Save product type specific data.
313: *
314: * @return Mage_ImportExport_Model_Import_Entity_Product_Type_Abstract
315: */
316: public function saveData()
317: {
318: return $this;
319: }
320: }
321: