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_Import extends Mage_ImportExport_Model_Abstract
35: {
36: 37: 38:
39: const CONFIG_KEY_ENTITIES = 'global/importexport/import_entities';
40:
41: 42: 43:
44: const BEHAVIOR_APPEND = 'append';
45: const BEHAVIOR_REPLACE = 'replace';
46: const BEHAVIOR_DELETE = 'delete';
47:
48: 49: 50:
51: const FIELD_NAME_SOURCE_FILE = 'import_file';
52: const FIELD_NAME_IMG_ARCHIVE_FILE = 'import_image_archive';
53:
54: 55: 56: 57:
58: const DEFAULT_SIZE = 50;
59: const MAX_IMPORT_CHUNKS = 4;
60:
61: 62: 63: 64: 65:
66: protected $_entityAdapter;
67:
68: 69: 70: 71: 72:
73: protected static $_entityInvalidatedIndexes = array (
74: 'catalog_product' => array (
75: 'catalog_product_price',
76: 'catalog_category_product',
77: 'catalogsearch_fulltext',
78: 'catalog_product_flat',
79: )
80: );
81:
82: 83: 84: 85: 86: 87:
88: protected function _getEntityAdapter()
89: {
90: if (!$this->_entityAdapter) {
91: $validTypes = Mage_ImportExport_Model_Config::getModels(self::CONFIG_KEY_ENTITIES);
92:
93: if (isset($validTypes[$this->getEntity()])) {
94: try {
95: $this->_entityAdapter = Mage::getModel($validTypes[$this->getEntity()]['model']);
96: } catch (Exception $e) {
97: Mage::logException($e);
98: Mage::throwException(
99: Mage::helper('importexport')->__('Invalid entity model')
100: );
101: }
102: if (!($this->_entityAdapter instanceof Mage_ImportExport_Model_Import_Entity_Abstract)) {
103: Mage::throwException(
104: Mage::helper('importexport')->__('Entity adapter object must be an instance of Mage_ImportExport_Model_Import_Entity_Abstract')
105: );
106: }
107: } else {
108: Mage::throwException(Mage::helper('importexport')->__('Invalid entity'));
109: }
110:
111: if ($this->getEntity() != $this->_entityAdapter->getEntityTypeCode()) {
112: Mage::throwException(
113: Mage::helper('importexport')->__('Input entity code is not equal to entity adapter code')
114: );
115: }
116: $this->_entityAdapter->setParameters($this->getData());
117: }
118: return $this->_entityAdapter;
119: }
120:
121: 122: 123: 124: 125: 126:
127: protected function _getSourceAdapter($sourceFile)
128: {
129: return Mage_ImportExport_Model_Import_Adapter::findAdapterFor($sourceFile);
130: }
131:
132: 133: 134: 135: 136: 137:
138: public function getOperationResultMessages($validationResult)
139: {
140: $messages = array();
141: if ($this->getProcessedRowsCount()) {
142: if (!$validationResult) {
143: if ($this->getProcessedRowsCount() == $this->getInvalidRowsCount()) {
144: $messages[] = Mage::helper('importexport')->__('File is totally invalid. Please fix errors and re-upload file');
145: } elseif ($this->getErrorsCount() >= $this->getErrorsLimit()) {
146: $messages[] = Mage::helper('importexport')->__('Errors limit (%d) reached. Please fix errors and re-upload file',
147: $this->getErrorsLimit()
148: );
149: } else {
150: if ($this->isImportAllowed()) {
151: $messages[] = Mage::helper('importexport')->__('Please fix errors and re-upload file');
152: } else {
153: $messages[] = Mage::helper('importexport')->__('File is partially valid, but import is not possible');
154: }
155: }
156:
157: foreach ($this->getErrors() as $errorCode => $rows) {
158: $error = $errorCode . ' '
159: . Mage::helper('importexport')->__('in rows') . ': '
160: . implode(', ', $rows);
161: $messages[] = $error;
162: }
163: } else {
164: if ($this->isImportAllowed()) {
165: $messages[] = Mage::helper('importexport')->__('Validation finished successfully');
166: } else {
167: $messages[] = Mage::helper('importexport')->__('File is valid, but import is not possible');
168: }
169: }
170: $notices = $this->getNotices();
171: if (is_array($notices)) {
172: $messages = array_merge($messages, $notices);
173: }
174: $messages[] = Mage::helper('importexport')->__('Checked rows: %d, checked entities: %d, invalid rows: %d, total errors: %d',
175: $this->getProcessedRowsCount(), $this->getProcessedEntitiesCount(),
176: $this->getInvalidRowsCount(), $this->getErrorsCount()
177: );
178: } else {
179: $messages[] = Mage::helper('importexport')->__('File does not contain data.');
180: }
181: return $messages;
182: }
183:
184: 185: 186: 187: 188: 189:
190: public static function getAttributeType(Mage_Eav_Model_Entity_Attribute $attribute)
191: {
192: if ($attribute->usesSource()) {
193: return $attribute->getFrontendInput() == 'multiselect' ?
194: 'multiselect' : 'select';
195: } elseif ($attribute->isStatic()) {
196: return $attribute->getFrontendInput() == 'date' ? 'datetime' : 'varchar';
197: } else {
198: return $attribute->getBackendType();
199: }
200: }
201:
202: 203: 204: 205: 206: 207:
208: public static function getDataSourceModel()
209: {
210: return Mage::getResourceSingleton('importexport/import_data');
211: }
212:
213: 214: 215: 216: 217: 218:
219: public static function getDefaultBehavior()
220: {
221: return self::BEHAVIOR_APPEND;
222: }
223:
224: 225: 226: 227: 228: 229:
230: public function getEntity()
231: {
232: if (empty($this->_data['entity'])) {
233: Mage::throwException(Mage::helper('importexport')->__('Entity is unknown'));
234: }
235: return $this->_data['entity'];
236: }
237:
238: 239: 240: 241: 242:
243: public function getErrors()
244: {
245: return $this->_getEntityAdapter()->getErrorMessages();
246: }
247:
248: 249: 250: 251: 252:
253: public function getErrorsCount()
254: {
255: return $this->_getEntityAdapter()->getErrorsCount();
256: }
257:
258: 259: 260: 261: 262:
263: public function getErrorsLimit()
264: {
265: return $this->_getEntityAdapter()->getErrorsLimit();
266: }
267:
268: 269: 270: 271: 272:
273: public function getInvalidRowsCount()
274: {
275: return $this->_getEntityAdapter()->getInvalidRowsCount();
276: }
277:
278: 279: 280: 281: 282:
283: public function getNotices()
284: {
285: return $this->_getEntityAdapter()->getNotices();
286: }
287:
288: 289: 290: 291: 292:
293: public function getProcessedEntitiesCount()
294: {
295: return $this->_getEntityAdapter()->getProcessedEntitiesCount();
296: }
297:
298: 299: 300: 301: 302:
303: public function getProcessedRowsCount()
304: {
305: return $this->_getEntityAdapter()->getProcessedRowsCount();
306: }
307:
308: 309: 310: 311: 312:
313: public static function getWorkingDir()
314: {
315: return Mage::getBaseDir('var') . DS . 'importexport' . DS;
316: }
317:
318: 319: 320: 321: 322:
323: public function importSource()
324: {
325: $this->setData(array(
326: 'entity' => self::getDataSourceModel()->getEntityTypeCode(),
327: 'behavior' => self::getDataSourceModel()->getBehavior()
328: ));
329: $this->addLogComment(Mage::helper('importexport')->__('Begin import of "%s" with "%s" behavior', $this->getEntity(), $this->getBehavior()));
330: $result = $this->_getEntityAdapter()->importData();
331: $this->addLogComment(array(
332: Mage::helper('importexport')->__('Checked rows: %d, checked entities: %d, invalid rows: %d, total errors: %d',
333: $this->getProcessedRowsCount(), $this->getProcessedEntitiesCount(),
334: $this->getInvalidRowsCount(), $this->getErrorsCount()
335: ),
336: Mage::helper('importexport')->__('Import has been done successfuly.')
337: ));
338: return $result;
339: }
340:
341: 342: 343: 344: 345:
346: public function isImportAllowed()
347: {
348: return $this->_getEntityAdapter()->isImportAllowed();
349: }
350:
351: 352: 353: 354: 355:
356: public function expandSource()
357: {
358: $writer = Mage::getModel('importexport/export_adapter_csv', self::getWorkingDir() . "big0.csv");
359: $regExps = array('last' => '/(.*?)(\d+)$/', 'middle' => '/(.*?)(\d+)(.*)$/');
360: $colReg = array(
361: 'sku' => 'last', 'name' => 'last', 'description' => 'last', 'short_description' => 'last',
362: 'url_key' => 'middle', 'meta_title' => 'last', 'meta_keyword' => 'last', 'meta_description' => 'last',
363: '_links_related_sku' => 'last', '_links_crosssell_sku' => 'last', '_links_upsell_sku' => 'last',
364: '_custom_option_sku' => 'middle', '_custom_option_row_sku' => 'middle', '_super_products_sku' => 'last',
365: '_associated_sku' => 'last'
366: );
367: $size = self::DEFAULT_SIZE;
368:
369: $filename = 'catalog_product.csv';
370: $filenameFormat = 'big%s.csv';
371: foreach ($this->_getSourceAdapter(self::getWorkingDir() . $filename) as $row) {
372: $writer->writeRow($row);
373: }
374: $count = self::MAX_IMPORT_CHUNKS;
375: for ($i = 1; $i < $count; $i++) {
376: $writer = Mage::getModel(
377: 'importexport/export_adapter_csv',
378: self::getWorkingDir() . sprintf($filenameFormat, $i)
379: );
380:
381: $adapter = $this->_getSourceAdapter(self::getWorkingDir() . sprintf($filenameFormat, $i - 1));
382: foreach ($adapter as $row) {
383: $writer->writeRow($row);
384: }
385: $adapter = $this->_getSourceAdapter(self::getWorkingDir() . sprintf($filenameFormat, $i - 1));
386: foreach ($adapter as $row) {
387: foreach ($colReg as $colName => $regExpType) {
388: if (!empty($row[$colName])) {
389: preg_match($regExps[$regExpType], $row[$colName], $m);
390:
391: $row[$colName] = $m[1] . ($m[2] + $size) . ('middle' == $regExpType ? $m[3] : '');
392: }
393: }
394: $writer->writeRow($row);
395: }
396: $size *= 2;
397: }
398: }
399:
400: 401: 402: 403: 404: 405:
406: public function uploadSource()
407: {
408: $entity = $this->getEntity();
409: $uploader = Mage::getModel('core/file_uploader', self::FIELD_NAME_SOURCE_FILE);
410: $uploader->skipDbProcessing(true);
411: $result = $uploader->save(self::getWorkingDir());
412: $extension = pathinfo($result['file'], PATHINFO_EXTENSION);
413:
414: $uploadedFile = $result['path'] . $result['file'];
415: if (!$extension) {
416: unlink($uploadedFile);
417: Mage::throwException(Mage::helper('importexport')->__('Uploaded file has no extension'));
418: }
419: $sourceFile = self::getWorkingDir() . $entity;
420:
421: $sourceFile .= '.' . $extension;
422:
423: if(strtolower($uploadedFile) != strtolower($sourceFile)) {
424: if (file_exists($sourceFile)) {
425: unlink($sourceFile);
426: }
427:
428: if (!@rename($uploadedFile, $sourceFile)) {
429: Mage::throwException(Mage::helper('importexport')->__('Source file moving failed'));
430: }
431: }
432:
433: try {
434: $this->_getSourceAdapter($sourceFile);
435: } catch (Exception $e) {
436: unlink($sourceFile);
437: Mage::throwException($e->getMessage());
438: }
439: return $sourceFile;
440: }
441:
442: 443: 444: 445: 446: 447:
448: public function validateSource($sourceFile)
449: {
450: $this->addLogComment(Mage::helper('importexport')->__('Begin data validation'));
451: $result = $this->_getEntityAdapter()
452: ->setSource($this->_getSourceAdapter($sourceFile))
453: ->isDataValid();
454:
455: $messages = $this->getOperationResultMessages($result);
456: $this->addLogComment($messages);
457: if ($result) {
458: $this->addLogComment(Mage::helper('importexport')->__('Done import data validation'));
459: }
460: return $result;
461: }
462:
463: 464: 465: 466: 467:
468: public function invalidateIndex()
469: {
470: if (!isset(self::$_entityInvalidatedIndexes[$this->getEntity()])) {
471: return $this;
472: }
473:
474: $indexers = self::$_entityInvalidatedIndexes[$this->getEntity()];
475: foreach ($indexers as $indexer) {
476: $indexProcess = Mage::getSingleton('index/indexer')->getProcessByCode($indexer);
477: if ($indexProcess) {
478: $indexProcess->changeStatus(Mage_Index_Model_Process::STATUS_REQUIRE_REINDEX);
479: }
480: }
481:
482: return $this;
483: }
484: }
485:
486: