1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25:
26:
27: 28: 29: 30: 31: 32: 33:
34: class Mage_ImportExport_Model_Export_Entity_Product extends Mage_ImportExport_Model_Export_Entity_Abstract
35: {
36: const CONFIG_KEY_PRODUCT_TYPES = 'global/importexport/export_product_types';
37:
38: 39: 40:
41: const VALUE_ALL = 'all';
42:
43: 44: 45: 46: 47: 48:
49: const COL_STORE = '_store';
50: const COL_ATTR_SET = '_attribute_set';
51: const COL_TYPE = '_type';
52: const COL_CATEGORY = '_category';
53: const COL_ROOT_CATEGORY = '_root_category';
54: const COL_SKU = 'sku';
55:
56: 57: 58: 59: 60:
61: protected $_attrSetIdToName = array();
62:
63: 64: 65: 66: 67:
68: protected $_categories = array();
69:
70: 71: 72: 73: 74:
75: protected $_rootCategories = array();
76:
77: 78: 79: 80: 81:
82: protected $_indexValueAttributes = array(
83: 'status',
84: 'tax_class_id',
85: 'visibility',
86: 'enable_googlecheckout',
87: 'gift_message_available',
88: 'custom_design'
89: );
90:
91: 92: 93: 94: 95:
96: protected $_permanentAttributes = array(self::COL_SKU);
97:
98: 99: 100: 101: 102:
103: protected $_productTypeModels = array();
104:
105: 106: 107: 108: 109:
110: protected $_storeIdToCode = array();
111:
112: 113: 114: 115: 116:
117: protected $_websiteIdToCode = array();
118:
119: 120: 121: 122:
123: protected $_attributeTypes = array();
124:
125: 126: 127: 128: 129:
130: public function __construct()
131: {
132: parent::__construct();
133:
134: $this->_initTypeModels()
135: ->_initAttributes()
136: ->_initStores()
137: ->_initAttributeSets()
138: ->_initWebsites()
139: ->_initCategories();
140: }
141:
142: 143: 144: 145: 146:
147: protected function _initAttributeSets()
148: {
149: $productTypeId = Mage::getModel('catalog/product')->getResource()->getTypeId();
150: foreach (Mage::getResourceModel('eav/entity_attribute_set_collection')
151: ->setEntityTypeFilter($productTypeId) as $attributeSet) {
152: $this->_attrSetIdToName[$attributeSet->getId()] = $attributeSet->getAttributeSetName();
153: }
154: return $this;
155: }
156:
157: 158: 159: 160: 161:
162: protected function _initCategories()
163: {
164: $collection = Mage::getResourceModel('catalog/category_collection')->addNameToResult();
165:
166: foreach ($collection as $category) {
167: $structure = preg_split('#/+#', $category->getPath());
168: $pathSize = count($structure);
169: if ($pathSize > 1) {
170: $path = array();
171: for ($i = 1; $i < $pathSize; $i++) {
172: $path[] = $collection->getItemById($structure[$i])->getName();
173: }
174: $this->_rootCategories[$category->getId()] = array_shift($path);
175: if ($pathSize > 2) {
176: $this->_categories[$category->getId()] = implode('/', $path);
177: }
178: }
179:
180: }
181: return $this;
182: }
183:
184: 185: 186: 187: 188: 189:
190: protected function _initTypeModels()
191: {
192: $config = Mage::getConfig()->getNode(self::CONFIG_KEY_PRODUCT_TYPES)->asCanonicalArray();
193: foreach ($config as $type => $typeModel) {
194: if (!($model = Mage::getModel($typeModel, array($this, $type)))) {
195: Mage::throwException("Entity type model '{$typeModel}' is not found");
196: }
197: if (! $model instanceof Mage_ImportExport_Model_Export_Entity_Product_Type_Abstract) {
198: Mage::throwException(
199: Mage::helper('importexport')->__('Entity type model must be an instance of Mage_ImportExport_Model_Export_Entity_Product_Type_Abstract')
200: );
201: }
202: if ($model->isSuitable()) {
203: $this->_productTypeModels[$type] = $model;
204: $this->_disabledAttrs = array_merge($this->_disabledAttrs, $model->getDisabledAttrs());
205: $this->_indexValueAttributes = array_merge(
206: $this->_indexValueAttributes, $model->getIndexValueAttributes()
207: );
208: }
209: }
210: if (!$this->_productTypeModels) {
211: Mage::throwException(Mage::helper('importexport')->__('There are no product types available for export'));
212: }
213: $this->_disabledAttrs = array_unique($this->_disabledAttrs);
214:
215: return $this;
216: }
217:
218: 219: 220: 221: 222:
223: protected function _initWebsites()
224: {
225:
226: foreach (Mage::app()->getWebsites() as $website) {
227: $this->_websiteIdToCode[$website->getId()] = $website->getCode();
228: }
229: return $this;
230: }
231:
232: 233: 234: 235: 236: 237:
238: protected function _prepareTierPrices(array $productIds)
239: {
240: if (empty($productIds)) {
241: return array();
242: }
243: $resource = Mage::getSingleton('core/resource');
244: $select = $this->_connection->select()
245: ->from($resource->getTableName('catalog/product_attribute_tier_price'))
246: ->where('entity_id IN(?)', $productIds);
247:
248: $rowTierPrices = array();
249: $stmt = $this->_connection->query($select);
250: while ($tierRow = $stmt->fetch()) {
251: $rowTierPrices[$tierRow['entity_id']][] = array(
252: '_tier_price_customer_group' => $tierRow['all_groups']
253: ? self::VALUE_ALL : $tierRow['customer_group_id'],
254: '_tier_price_website' => 0 == $tierRow['website_id']
255: ? self::VALUE_ALL
256: : $this->_websiteIdToCode[$tierRow['website_id']],
257: '_tier_price_qty' => $tierRow['qty'],
258: '_tier_price_price' => $tierRow['value']
259: );
260: }
261:
262: return $rowTierPrices;
263: }
264:
265: 266: 267: 268: 269: 270:
271: protected function _prepareGroupPrices(array $productIds)
272: {
273: if (empty($productIds)) {
274: return array();
275: }
276: $resource = Mage::getSingleton('core/resource');
277: $select = $this->_connection->select()
278: ->from($resource->getTableName('catalog/product_attribute_group_price'))
279: ->where('entity_id IN(?)', $productIds);
280:
281: $rowGroupPrices = array();
282: $statement = $this->_connection->query($select);
283: while ($groupRow = $statement->fetch()) {
284: $rowGroupPrices[$groupRow['entity_id']][] = array(
285: '_group_price_customer_group' => $groupRow['all_groups']
286: ? self::VALUE_ALL
287: : $groupRow['customer_group_id'],
288: '_group_price_website' => (0 == $groupRow['website_id'])
289: ? self::VALUE_ALL
290: : $this->_websiteIdToCode[$groupRow['website_id']],
291: '_group_price_price' => $groupRow['value']
292: );
293: }
294:
295: return $rowGroupPrices;
296: }
297:
298: 299: 300: 301: 302: 303:
304: protected function _prepareMediaGallery(array $productIds)
305: {
306: if (empty($productIds)) {
307: return array();
308: }
309: $resource = Mage::getSingleton('core/resource');
310: $select = $this->_connection->select()
311: ->from(
312: array('mg' => $resource->getTableName('catalog/product_attribute_media_gallery')),
313: array(
314: 'mg.entity_id', 'mg.attribute_id', 'filename' => 'mg.value', 'mgv.label',
315: 'mgv.position', 'mgv.disabled'
316: )
317: )
318: ->joinLeft(
319: array('mgv' => $resource->getTableName('catalog/product_attribute_media_gallery_value')),
320: '(mg.value_id = mgv.value_id AND mgv.store_id = 0)',
321: array()
322: )
323: ->where('entity_id IN(?)', $productIds);
324:
325: $rowMediaGallery = array();
326: $stmt = $this->_connection->query($select);
327: while ($mediaRow = $stmt->fetch()) {
328: $rowMediaGallery[$mediaRow['entity_id']][] = array(
329: '_media_attribute_id' => $mediaRow['attribute_id'],
330: '_media_image' => $mediaRow['filename'],
331: '_media_lable' => $mediaRow['label'],
332: '_media_position' => $mediaRow['position'],
333: '_media_is_disabled' => $mediaRow['disabled']
334: );
335: }
336:
337: return $rowMediaGallery;
338: }
339:
340: 341: 342: 343: 344: 345:
346: protected function _prepareCatalogInventory(array $productIds)
347: {
348: if (empty($productIds)) {
349: return array();
350: }
351: $select = $this->_connection->select()
352: ->from(Mage::getResourceModel('cataloginventory/stock_item')->getMainTable())
353: ->where('product_id IN (?)', $productIds);
354:
355: $stmt = $this->_connection->query($select);
356: $stockItemRows = array();
357: while ($stockItemRow = $stmt->fetch()) {
358: $productId = $stockItemRow['product_id'];
359: unset(
360: $stockItemRow['item_id'], $stockItemRow['product_id'], $stockItemRow['low_stock_date'],
361: $stockItemRow['stock_id'], $stockItemRow['stock_status_changed_automatically']
362: );
363: $stockItemRows[$productId] = $stockItemRow;
364: }
365: return $stockItemRows;
366: }
367:
368: 369: 370: 371: 372: 373:
374: protected function _prepareLinks(array $productIds)
375: {
376: if (empty($productIds)) {
377: return array();
378: }
379: $resource = Mage::getSingleton('core/resource');
380: $adapter = $this->_connection;
381: $select = $adapter->select()
382: ->from(
383: array('cpl' => $resource->getTableName('catalog/product_link')),
384: array(
385: 'cpl.product_id', 'cpe.sku', 'cpl.link_type_id',
386: 'position' => 'cplai.value', 'default_qty' => 'cplad.value'
387: )
388: )
389: ->joinLeft(
390: array('cpe' => $resource->getTableName('catalog/product')),
391: '(cpe.entity_id = cpl.linked_product_id)',
392: array()
393: )
394: ->joinLeft(
395: array('cpla' => $resource->getTableName('catalog/product_link_attribute')),
396: $adapter->quoteInto(
397: '(cpla.link_type_id = cpl.link_type_id AND cpla.product_link_attribute_code = ?)',
398: 'position'
399: ),
400: array()
401: )
402: ->joinLeft(
403: array('cplaq' => $resource->getTableName('catalog/product_link_attribute')),
404: $adapter->quoteInto(
405: '(cplaq.link_type_id = cpl.link_type_id AND cplaq.product_link_attribute_code = ?)',
406: 'qty'
407: ),
408: array()
409: )
410: ->joinLeft(
411: array('cplai' => $resource->getTableName('catalog/product_link_attribute_int')),
412: '(cplai.link_id = cpl.link_id AND cplai.product_link_attribute_id = cpla.product_link_attribute_id)',
413: array()
414: )
415: ->joinLeft(
416: array('cplad' => $resource->getTableName('catalog/product_link_attribute_decimal')),
417: '(cplad.link_id = cpl.link_id AND cplad.product_link_attribute_id = cplaq.product_link_attribute_id)',
418: array()
419: )
420: ->where('cpl.link_type_id IN (?)', array(
421: Mage_Catalog_Model_Product_Link::LINK_TYPE_RELATED,
422: Mage_Catalog_Model_Product_Link::LINK_TYPE_UPSELL,
423: Mage_Catalog_Model_Product_Link::LINK_TYPE_CROSSSELL,
424: Mage_Catalog_Model_Product_Link::LINK_TYPE_GROUPED
425: ))
426: ->where('cpl.product_id IN (?)', $productIds);
427:
428: $stmt = $adapter->query($select);
429: $linksRows = array();
430: while ($linksRow = $stmt->fetch()) {
431: $linksRows[$linksRow['product_id']][$linksRow['link_type_id']][] = array(
432: 'sku' => $linksRow['sku'],
433: 'position' => $linksRow['position'],
434: 'default_qty' => $linksRow['default_qty']
435: );
436: }
437:
438: return $linksRows;
439: }
440:
441: 442: 443: 444: 445: 446: 447: 448:
449: protected function _prepareConfigurableProductData(array $productIds)
450: {
451: if (empty($productIds)) {
452: return array();
453: }
454: $resource = Mage::getSingleton('core/resource');
455: $select = $this->_connection->select()
456: ->from(
457: array('cpsl' => $resource->getTableName('catalog/product_super_link')),
458: array('cpsl.parent_id', 'cpe.sku')
459: )
460: ->joinLeft(
461: array('cpe' => $resource->getTableName('catalog/product')),
462: '(cpe.entity_id = cpsl.product_id)',
463: array()
464: )
465: ->where('parent_id IN (?)', $productIds);
466: $stmt = $this->_connection->query($select);
467: $configurableData = array();
468: while ($cfgLinkRow = $stmt->fetch()) {
469: $configurableData[$cfgLinkRow['parent_id']][] = array('_super_products_sku' => $cfgLinkRow['sku']);
470: }
471:
472: return $configurableData;
473: }
474:
475: 476: 477: 478: 479: 480: 481: 482:
483: protected function _prepareConfigurableProductPrice(array $productIds)
484: {
485: if (empty($productIds)) {
486: return array();
487: }
488: $resource = Mage::getSingleton('core/resource');
489: $select = $this->_connection->select()
490: ->from(
491: array('cpsa' => $resource->getTableName('catalog/product_super_attribute')),
492: array(
493: 'cpsa.product_id', 'ea.attribute_code', 'eaov.value', 'cpsap.pricing_value', 'cpsap.is_percent'
494: )
495: )
496: ->joinLeft(
497: array('cpsap' => $resource->getTableName('catalog/product_super_attribute_pricing')),
498: '(cpsap.product_super_attribute_id = cpsa.product_super_attribute_id)',
499: array()
500: )
501: ->joinLeft(
502: array('ea' => $resource->getTableName('eav/attribute')),
503: '(ea.attribute_id = cpsa.attribute_id)',
504: array()
505: )
506: ->joinLeft(
507: array('eaov' => $resource->getTableName('eav/attribute_option_value')),
508: '(eaov.option_id = cpsap.value_index AND store_id = 0)',
509: array()
510: )
511: ->where('cpsa.product_id IN (?)', $productIds);
512: $configurablePrice = array();
513: $stmt = $this->_connection->query($select);
514: while ($priceRow = $stmt->fetch()) {
515: $configurablePrice[$priceRow['product_id']][] = array(
516: '_super_attribute_code' => $priceRow['attribute_code'],
517: '_super_attribute_option' => $priceRow['value'],
518: '_super_attribute_price_corr' => $priceRow['pricing_value'] . ($priceRow['is_percent'] ? '%' : '')
519: );
520: }
521: return $configurablePrice;
522: }
523:
524: 525: 526: 527: 528: 529: 530: 531:
532: protected function _updateDataWithCategoryColumns(&$dataRow, &$rowCategories, $productId)
533: {
534: if (!isset($rowCategories[$productId])) {
535: return false;
536: }
537:
538: $categoryId = array_shift($rowCategories[$productId]);
539: $dataRow[self::COL_ROOT_CATEGORY] = $this->_rootCategories[$categoryId];
540: if (isset($this->_categories[$categoryId])) {
541: $dataRow[self::COL_CATEGORY] = $this->_categories[$categoryId];
542: }
543:
544: return true;
545: }
546:
547: 548: 549: 550: 551:
552: public function export()
553: {
554:
555: set_time_limit(0);
556:
557:
558: $validAttrCodes = $this->_getExportAttrCodes();
559: $writer = $this->getWriter();
560: $defaultStoreId = Mage_Catalog_Model_Abstract::DEFAULT_STORE_ID;
561:
562: $memoryLimit = trim(ini_get('memory_limit'));
563: $lastMemoryLimitLetter = strtolower($memoryLimit[strlen($memoryLimit)-1]);
564: switch($lastMemoryLimitLetter) {
565: case 'g':
566: $memoryLimit *= 1024;
567: case 'm':
568: $memoryLimit *= 1024;
569: case 'k':
570: $memoryLimit *= 1024;
571: break;
572: default:
573:
574: $memoryLimit = 250000000;
575: }
576:
577:
578: $memoryPerProduct = 100000;
579:
580: $memoryUsagePercent = 0.8;
581:
582: $minProductsLimit = 500;
583:
584: $limitProducts = intval(($memoryLimit * $memoryUsagePercent - memory_get_usage(true)) / $memoryPerProduct);
585: if ($limitProducts < $minProductsLimit) {
586: $limitProducts = $minProductsLimit;
587: }
588: $offsetProducts = 0;
589:
590: while (true) {
591: ++$offsetProducts;
592:
593: $dataRows = array();
594: $rowCategories = array();
595: $rowWebsites = array();
596: $rowTierPrices = array();
597: $rowGroupPrices = array();
598: $rowMultiselects = array();
599: $mediaGalery = array();
600:
601:
602: foreach ($this->_storeIdToCode as $storeId => &$storeCode) {
603: $collection = $this->_prepareEntityCollection(Mage::getResourceModel('catalog/product_collection'));
604: $collection
605: ->setStoreId($storeId)
606: ->setPage($offsetProducts, $limitProducts);
607: if ($collection->getCurPage() < $offsetProducts) {
608: break;
609: }
610: $collection->load();
611:
612: if ($collection->count() == 0) {
613: break;
614: }
615:
616: if ($defaultStoreId == $storeId) {
617: $collection->addCategoryIds()->addWebsiteNamesToResult();
618:
619:
620: $rowTierPrices = $this->_prepareTierPrices($collection->getAllIds());
621: $rowGroupPrices = $this->_prepareGroupPrices($collection->getAllIds());
622:
623:
624: $mediaGalery = $this->_prepareMediaGallery($collection->getAllIds());
625: }
626: foreach ($collection as $itemId => $item) {
627: $rowIsEmpty = true;
628:
629: foreach ($validAttrCodes as &$attrCode) {
630: $attrValue = $item->getData($attrCode);
631:
632: if (!empty($this->_attributeValues[$attrCode])) {
633: if ($this->_attributeTypes[$attrCode] == 'multiselect') {
634: $attrValue = explode(',', $attrValue);
635: $attrValue = array_intersect_key(
636: $this->_attributeValues[$attrCode],
637: array_flip($attrValue)
638: );
639: $rowMultiselects[$itemId][$attrCode] = $attrValue;
640: } else if (isset($this->_attributeValues[$attrCode][$attrValue])) {
641: $attrValue = $this->_attributeValues[$attrCode][$attrValue];
642: } else {
643: $attrValue = null;
644: }
645: }
646:
647: if ($storeId != $defaultStoreId
648: && isset($dataRows[$itemId][$defaultStoreId][$attrCode])
649: && $dataRows[$itemId][$defaultStoreId][$attrCode] == $attrValue
650: ) {
651: $attrValue = null;
652: }
653: if (is_scalar($attrValue)) {
654: $dataRows[$itemId][$storeId][$attrCode] = $attrValue;
655: $rowIsEmpty = false;
656: }
657: }
658: if ($rowIsEmpty) {
659: unset($dataRows[$itemId][$storeId]);
660: } else {
661: $attrSetId = $item->getAttributeSetId();
662: $dataRows[$itemId][$storeId][self::COL_STORE] = $storeCode;
663: $dataRows[$itemId][$storeId][self::COL_ATTR_SET] = $this->_attrSetIdToName[$attrSetId];
664: $dataRows[$itemId][$storeId][self::COL_TYPE] = $item->getTypeId();
665:
666: if ($defaultStoreId == $storeId) {
667: $rowWebsites[$itemId] = $item->getWebsites();
668: $rowCategories[$itemId] = $item->getCategoryIds();
669: }
670: }
671: $item = null;
672: }
673: $collection->clear();
674: }
675:
676: if ($collection->getCurPage() < $offsetProducts) {
677: break;
678: }
679:
680:
681: $allCategoriesIds = array_merge(array_keys($this->_categories), array_keys($this->_rootCategories));
682: foreach ($rowCategories as &$categories) {
683: $categories = array_intersect($categories, $allCategoriesIds);
684: }
685:
686:
687: $productIds = array_keys($dataRows);
688: $stockItemRows = $this->_prepareCatalogInventory($productIds);
689:
690:
691: $linksRows = $this->_prepareLinks($productIds);
692: $linkIdColPrefix = array(
693: Mage_Catalog_Model_Product_Link::LINK_TYPE_RELATED => '_links_related_',
694: Mage_Catalog_Model_Product_Link::LINK_TYPE_UPSELL => '_links_upsell_',
695: Mage_Catalog_Model_Product_Link::LINK_TYPE_CROSSSELL => '_links_crosssell_',
696: Mage_Catalog_Model_Product_Link::LINK_TYPE_GROUPED => '_associated_'
697: );
698: $configurableProductsCollection = Mage::getResourceModel('catalog/product_collection');
699: $configurableProductsCollection->addAttributeToFilter(
700: 'entity_id',
701: array(
702: 'in' => $productIds
703: )
704: )->addAttributeToFilter(
705: 'type_id',
706: array(
707: 'eq' => Mage_Catalog_Model_Product_Type_Configurable::TYPE_CODE
708: )
709: );
710: $configurableData = array();
711: while ($product = $configurableProductsCollection->fetchItem()) {
712: $productAttributesOptions = $product->getTypeInstance(true)->getConfigurableOptions($product);
713:
714: foreach ($productAttributesOptions as $productAttributeOption) {
715: $configurableData[$product->getId()] = array();
716: foreach ($productAttributeOption as $optionValues) {
717: $configurableData[$product->getId()][] = array(
718: '_super_products_sku' => $optionValues['sku'],
719: '_super_attribute_code' => $optionValues['attribute_code'],
720: '_super_attribute_option' => $optionValues['option_title'],
721: '_super_attribute_price_corr' => $optionValues['pricing_value']
722: );
723: }
724: }
725: }
726:
727:
728: $customOptionsData = array();
729: $customOptionsDataPre = array();
730: $customOptCols = array(
731: '_custom_option_store', '_custom_option_type', '_custom_option_title', '_custom_option_is_required',
732: '_custom_option_price', '_custom_option_sku', '_custom_option_max_characters',
733: '_custom_option_sort_order', '_custom_option_row_title', '_custom_option_row_price',
734: '_custom_option_row_sku', '_custom_option_row_sort'
735: );
736:
737: foreach ($this->_storeIdToCode as $storeId => &$storeCode) {
738: $options = Mage::getResourceModel('catalog/product_option_collection')
739: ->reset()
740: ->addTitleToResult($storeId)
741: ->addPriceToResult($storeId)
742: ->addProductToFilter($productIds)
743: ->addValuesToResult($storeId);
744:
745: foreach ($options as $option) {
746: $row = array();
747: $productId = $option['product_id'];
748: $optionId = $option['option_id'];
749: $customOptions = isset($customOptionsDataPre[$productId][$optionId])
750: ? $customOptionsDataPre[$productId][$optionId]
751: : array();
752:
753: if ($defaultStoreId == $storeId) {
754: $row['_custom_option_type'] = $option['type'];
755: $row['_custom_option_title'] = $option['title'];
756: $row['_custom_option_is_required'] = $option['is_require'];
757: $row['_custom_option_price'] = $option['price']
758: . ($option['price_type'] == 'percent' ? '%' : '');
759: $row['_custom_option_sku'] = $option['sku'];
760: $row['_custom_option_max_characters'] = $option['max_characters'];
761: $row['_custom_option_sort_order'] = $option['sort_order'];
762:
763:
764: $defaultTitles[$option['option_id']] = $option['title'];
765: } elseif ($option['title'] != $customOptions[0]['_custom_option_title']) {
766: $row['_custom_option_title'] = $option['title'];
767: }
768: $values = $option->getValues();
769: if ($values) {
770: $firstValue = array_shift($values);
771: $priceType = $firstValue['price_type'] == 'percent' ? '%' : '';
772:
773: if ($defaultStoreId == $storeId) {
774: $row['_custom_option_row_title'] = $firstValue['title'];
775: $row['_custom_option_row_price'] = $firstValue['price'] . $priceType;
776: $row['_custom_option_row_sku'] = $firstValue['sku'];
777: $row['_custom_option_row_sort'] = $firstValue['sort_order'];
778:
779: $defaultValueTitles[$firstValue['option_type_id']] = $firstValue['title'];
780: } elseif ($firstValue['title'] != $customOptions[0]['_custom_option_row_title']) {
781: $row['_custom_option_row_title'] = $firstValue['title'];
782: }
783: }
784: if ($row) {
785: if ($defaultStoreId != $storeId) {
786: $row['_custom_option_store'] = $this->_storeIdToCode[$storeId];
787: }
788: $customOptionsDataPre[$productId][$optionId][] = $row;
789: }
790: foreach ($values as $value) {
791: $row = array();
792: $valuePriceType = $value['price_type'] == 'percent' ? '%' : '';
793:
794: if ($defaultStoreId == $storeId) {
795: $row['_custom_option_row_title'] = $value['title'];
796: $row['_custom_option_row_price'] = $value['price'] . $valuePriceType;
797: $row['_custom_option_row_sku'] = $value['sku'];
798: $row['_custom_option_row_sort'] = $value['sort_order'];
799: } elseif ($value['title'] != $customOptions[0]['_custom_option_row_title']) {
800: $row['_custom_option_row_title'] = $value['title'];
801: }
802: if ($row) {
803: if ($defaultStoreId != $storeId) {
804: $row['_custom_option_store'] = $this->_storeIdToCode[$storeId];
805: }
806: $customOptionsDataPre[$option['product_id']][$option['option_id']][] = $row;
807: }
808: }
809: $option = null;
810: }
811: $options = null;
812: }
813: foreach ($customOptionsDataPre as $productId => &$optionsData) {
814: $customOptionsData[$productId] = array();
815:
816: foreach ($optionsData as $optionId => &$optionRows) {
817: $customOptionsData[$productId] = array_merge($customOptionsData[$productId], $optionRows);
818: }
819: unset($optionRows, $optionsData);
820: }
821: unset($customOptionsDataPre);
822:
823: if ($offsetProducts == 1) {
824:
825: $headerCols = array_merge(
826: array(
827: self::COL_SKU, self::COL_STORE, self::COL_ATTR_SET,
828: self::COL_TYPE, self::COL_CATEGORY, self::COL_ROOT_CATEGORY, '_product_websites'
829: ),
830: $validAttrCodes,
831: reset($stockItemRows) ? array_keys(end($stockItemRows)) : array(),
832: array(),
833: array(
834: '_links_related_sku', '_links_related_position', '_links_crosssell_sku',
835: '_links_crosssell_position', '_links_upsell_sku', '_links_upsell_position',
836: '_associated_sku', '_associated_default_qty', '_associated_position'
837: ),
838: array('_tier_price_website', '_tier_price_customer_group', '_tier_price_qty', '_tier_price_price'),
839: array('_group_price_website', '_group_price_customer_group', '_group_price_price'),
840: array(
841: '_media_attribute_id',
842: '_media_image',
843: '_media_lable',
844: '_media_position',
845: '_media_is_disabled'
846: )
847: );
848:
849:
850: if ($customOptionsData) {
851: $headerCols = array_merge($headerCols, $customOptCols);
852: }
853:
854:
855: if ($configurableData) {
856: $headerCols = array_merge($headerCols, array(
857: '_super_products_sku', '_super_attribute_code',
858: '_super_attribute_option', '_super_attribute_price_corr'
859: ));
860: }
861:
862: $writer->setHeaderCols($headerCols);
863: }
864:
865: foreach ($dataRows as $productId => &$productData) {
866: foreach ($productData as $storeId => &$dataRow) {
867: if ($defaultStoreId != $storeId) {
868: $dataRow[self::COL_SKU] = null;
869: $dataRow[self::COL_ATTR_SET] = null;
870: $dataRow[self::COL_TYPE] = null;
871: } else {
872: $dataRow[self::COL_STORE] = null;
873: $dataRow += $stockItemRows[$productId];
874: }
875:
876: $this->_updateDataWithCategoryColumns($dataRow, $rowCategories, $productId);
877: if ($rowWebsites[$productId]) {
878: $dataRow['_product_websites'] = $this->_websiteIdToCode[array_shift($rowWebsites[$productId])];
879: }
880: if (!empty($rowTierPrices[$productId])) {
881: $dataRow = array_merge($dataRow, array_shift($rowTierPrices[$productId]));
882: }
883: if (!empty($rowGroupPrices[$productId])) {
884: $dataRow = array_merge($dataRow, array_shift($rowGroupPrices[$productId]));
885: }
886: if (!empty($mediaGalery[$productId])) {
887: $dataRow = array_merge($dataRow, array_shift($mediaGalery[$productId]));
888: }
889: foreach ($linkIdColPrefix as $linkId => &$colPrefix) {
890: if (!empty($linksRows[$productId][$linkId])) {
891: $linkData = array_shift($linksRows[$productId][$linkId]);
892: $dataRow[$colPrefix . 'position'] = $linkData['position'];
893: $dataRow[$colPrefix . 'sku'] = $linkData['sku'];
894:
895: if (null !== $linkData['default_qty']) {
896: $dataRow[$colPrefix . 'default_qty'] = $linkData['default_qty'];
897: }
898: }
899: }
900: if (!empty($customOptionsData[$productId])) {
901: $dataRow = array_merge($dataRow, array_shift($customOptionsData[$productId]));
902: }
903: if (!empty($configurableData[$productId])) {
904: $dataRow = array_merge($dataRow, array_shift($configurableData[$productId]));
905: }
906: if(!empty($rowMultiselects[$productId])) {
907: foreach ($rowMultiselects[$productId] as $attrKey => $attrVal) {
908: if (!empty($rowMultiselects[$productId][$attrKey])) {
909: $dataRow[$attrKey] = array_shift($rowMultiselects[$productId][$attrKey]);
910: }
911: }
912: }
913:
914: $writer->writeRow($dataRow);
915: }
916:
917: $largestLinks = 0;
918:
919: if (isset($linksRows[$productId])) {
920: $linksRowsKeys = array_keys($linksRows[$productId]);
921: foreach ($linksRowsKeys as $linksRowsKey) {
922: $largestLinks = max($largestLinks, count($linksRows[$productId][$linksRowsKey]));
923: }
924: }
925: $additionalRowsCount = max(
926: count($rowCategories[$productId]),
927: count($rowWebsites[$productId]),
928: $largestLinks
929: );
930: if (!empty($rowTierPrices[$productId])) {
931: $additionalRowsCount = max($additionalRowsCount, count($rowTierPrices[$productId]));
932: }
933: if (!empty($rowGroupPrices[$productId])) {
934: $additionalRowsCount = max($additionalRowsCount, count($rowGroupPrices[$productId]));
935: }
936: if (!empty($mediaGalery[$productId])) {
937: $additionalRowsCount = max($additionalRowsCount, count($mediaGalery[$productId]));
938: }
939: if (!empty($customOptionsData[$productId])) {
940: $additionalRowsCount = max($additionalRowsCount, count($customOptionsData[$productId]));
941: }
942: if (!empty($configurableData[$productId])) {
943: $additionalRowsCount = max($additionalRowsCount, count($configurableData[$productId]));
944: }
945: if (!empty($rowMultiselects[$productId])) {
946: foreach($rowMultiselects[$productId] as $attributes) {
947: $additionalRowsCount = max($additionalRowsCount, count($attributes));
948: }
949: }
950:
951: if ($additionalRowsCount) {
952: for ($i = 0; $i < $additionalRowsCount; $i++) {
953: $dataRow = array();
954:
955: $this->_updateDataWithCategoryColumns($dataRow, $rowCategories, $productId);
956: if ($rowWebsites[$productId]) {
957: $dataRow['_product_websites'] = $this
958: ->_websiteIdToCode[array_shift($rowWebsites[$productId])];
959: }
960: if (!empty($rowTierPrices[$productId])) {
961: $dataRow = array_merge($dataRow, array_shift($rowTierPrices[$productId]));
962: }
963: if (!empty($rowGroupPrices[$productId])) {
964: $dataRow = array_merge($dataRow, array_shift($rowGroupPrices[$productId]));
965: }
966: if (!empty($mediaGalery[$productId])) {
967: $dataRow = array_merge($dataRow, array_shift($mediaGalery[$productId]));
968: }
969: foreach ($linkIdColPrefix as $linkId => &$colPrefix) {
970: if (!empty($linksRows[$productId][$linkId])) {
971: $linkData = array_shift($linksRows[$productId][$linkId]);
972: $dataRow[$colPrefix . 'position'] = $linkData['position'];
973: $dataRow[$colPrefix . 'sku'] = $linkData['sku'];
974:
975: if (null !== $linkData['default_qty']) {
976: $dataRow[$colPrefix . 'default_qty'] = $linkData['default_qty'];
977: }
978: }
979: }
980: if (!empty($customOptionsData[$productId])) {
981: $dataRow = array_merge($dataRow, array_shift($customOptionsData[$productId]));
982: }
983: if (!empty($configurableData[$productId])) {
984: $dataRow = array_merge($dataRow, array_shift($configurableData[$productId]));
985: }
986: if(!empty($rowMultiselects[$productId])) {
987: foreach($rowMultiselects[$productId] as $attrKey=>$attrVal) {
988: if(!empty($rowMultiselects[$productId][$attrKey])) {
989: $dataRow[$attrKey] = array_shift($rowMultiselects[$productId][$attrKey]);
990: }
991: }
992: }
993: $writer->writeRow($dataRow);
994: }
995: }
996: }
997: }
998: return $writer->getContents();
999: }
1000:
1001: 1002: 1003: 1004: 1005: 1006:
1007: public function filterAttributeCollection(Mage_Eav_Model_Resource_Entity_Attribute_Collection $collection)
1008: {
1009: $validTypes = array_keys($this->_productTypeModels);
1010:
1011: foreach (parent::filterAttributeCollection($collection) as $attribute) {
1012: $attrApplyTo = $attribute->getApplyTo();
1013: $attrApplyTo = $attrApplyTo ? array_intersect($attrApplyTo, $validTypes) : $validTypes;
1014:
1015: if ($attrApplyTo) {
1016: foreach ($attrApplyTo as $productType) {
1017: if ($this->_productTypeModels[$productType]->overrideAttribute($attribute)) {
1018: break;
1019: }
1020: }
1021: } else {
1022: $collection->removeItemByKey($attribute->getId());
1023: }
1024: }
1025: return $collection;
1026: }
1027:
1028: 1029: 1030: 1031: 1032:
1033: public function getAttributeCollection()
1034: {
1035: return Mage::getResourceModel('catalog/product_attribute_collection');
1036: }
1037:
1038: 1039: 1040: 1041: 1042:
1043: public function getEntityTypeCode()
1044: {
1045: return 'catalog_product';
1046: }
1047:
1048: 1049: 1050: 1051: 1052:
1053: protected function _initAttributes()
1054: {
1055: foreach ($this->getAttributeCollection() as $attribute) {
1056: $this->_attributeValues[$attribute->getAttributeCode()] = $this->getAttributeOptions($attribute);
1057: $this->_attributeTypes[$attribute->getAttributeCode()] =
1058: Mage_ImportExport_Model_Import::getAttributeType($attribute);
1059: }
1060: return $this;
1061: }
1062:
1063: }
1064: