Customer.php 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\CustomerImportExport\Model\Import;
  7. use Magento\Customer\Api\Data\CustomerInterface;
  8. use Magento\ImportExport\Model\Import;
  9. use Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregatorInterface;
  10. use Magento\ImportExport\Model\Import\AbstractSource;
  11. /**
  12. * Customer entity import
  13. *
  14. * @api
  15. *
  16. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  17. * @since 100.0.2
  18. */
  19. class Customer extends AbstractCustomer
  20. {
  21. /**
  22. * Attribute collection name
  23. */
  24. const ATTRIBUTE_COLLECTION_NAME = \Magento\Customer\Model\ResourceModel\Attribute\Collection::class;
  25. /**#@+
  26. * Permanent column names
  27. *
  28. * Names that begins with underscore is not an attribute. This name convention is for
  29. * to avoid interference with same attribute name.
  30. */
  31. const COLUMN_EMAIL = 'email';
  32. const COLUMN_STORE = '_store';
  33. const COLUMN_PASSWORD = 'password';
  34. /**#@-*/
  35. /**#@+
  36. * Error codes
  37. */
  38. const ERROR_DUPLICATE_EMAIL_SITE = 'duplicateEmailSite';
  39. const ERROR_ROW_IS_ORPHAN = 'rowIsOrphan';
  40. const ERROR_INVALID_STORE = 'invalidStore';
  41. const ERROR_EMAIL_SITE_NOT_FOUND = 'emailSiteNotFound';
  42. const ERROR_PASSWORD_LENGTH = 'passwordLength';
  43. /**#@-*/
  44. /**#@+
  45. * Keys which used to build result data array for future update
  46. */
  47. const ENTITIES_TO_CREATE_KEY = 'entities_to_create';
  48. const ENTITIES_TO_UPDATE_KEY = 'entities_to_update';
  49. const ATTRIBUTES_TO_SAVE_KEY = 'attributes_to_save';
  50. /**#@-*/
  51. /**
  52. * Minimum password length
  53. */
  54. const MIN_PASSWORD_LENGTH = 6;
  55. /**
  56. * Default customer group
  57. */
  58. const DEFAULT_GROUP_ID = 1;
  59. /**
  60. * Customers information from import file
  61. *
  62. * @var array
  63. */
  64. protected $_newCustomers = [];
  65. /**
  66. * Array of attribute codes which will be ignored in validation and import procedures.
  67. * For example, when entity attribute has own validation and import procedures
  68. * or just to deny this attribute processing.
  69. *
  70. * @var string[]
  71. */
  72. protected $_ignoredAttributes = ['website_id', 'store_id'];
  73. /**
  74. * Customer entity DB table name.
  75. *
  76. * @var string
  77. */
  78. protected $_entityTable;
  79. /**
  80. * Customer model
  81. *
  82. * @var \Magento\Customer\Model\Customer
  83. */
  84. protected $_customerModel;
  85. /**
  86. * Id of next customer entity row
  87. *
  88. * @var int
  89. */
  90. protected $_nextEntityId;
  91. /**
  92. * Address attributes collection
  93. *
  94. * @var \Magento\Customer\Model\ResourceModel\Attribute\Collection
  95. */
  96. protected $_attributeCollection;
  97. /**
  98. * @var \Magento\ImportExport\Model\ResourceModel\Helper
  99. */
  100. protected $_resourceHelper;
  101. /**
  102. * {@inheritdoc}
  103. */
  104. protected $masterAttributeCode = 'email';
  105. /**
  106. * Valid column names
  107. *
  108. * @array
  109. */
  110. protected $validColumnNames = [
  111. self::COLUMN_DEFAULT_BILLING,
  112. self::COLUMN_DEFAULT_SHIPPING,
  113. self::COLUMN_PASSWORD,
  114. ];
  115. /**
  116. * Customer fields in file
  117. */
  118. protected $customerFields = [
  119. CustomerInterface::GROUP_ID,
  120. CustomerInterface::STORE_ID,
  121. CustomerInterface::UPDATED_AT,
  122. CustomerInterface::CREATED_AT,
  123. CustomerInterface::CREATED_IN,
  124. CustomerInterface::PREFIX,
  125. CustomerInterface::FIRSTNAME,
  126. CustomerInterface::MIDDLENAME,
  127. CustomerInterface::LASTNAME,
  128. CustomerInterface::SUFFIX,
  129. CustomerInterface::DOB,
  130. 'password_hash',
  131. CustomerInterface::TAXVAT,
  132. CustomerInterface::CONFIRMATION,
  133. CustomerInterface::GENDER,
  134. 'rp_token',
  135. 'rp_token_created_at',
  136. 'failures_num',
  137. 'first_failure',
  138. 'lock_expires',
  139. ];
  140. /**
  141. * @param \Magento\Framework\Stdlib\StringUtils $string
  142. * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
  143. * @param \Magento\ImportExport\Model\ImportFactory $importFactory
  144. * @param \Magento\ImportExport\Model\ResourceModel\Helper $resourceHelper
  145. * @param \Magento\Framework\App\ResourceConnection $resource
  146. * @param ProcessingErrorAggregatorInterface $errorAggregator
  147. * @param \Magento\Store\Model\StoreManagerInterface $storeManager
  148. * @param \Magento\ImportExport\Model\Export\Factory $collectionFactory
  149. * @param \Magento\Eav\Model\Config $eavConfig
  150. * @param \Magento\CustomerImportExport\Model\ResourceModel\Import\Customer\StorageFactory $storageFactory
  151. * @param \Magento\Customer\Model\ResourceModel\Attribute\CollectionFactory $attrCollectionFactory
  152. * @param \Magento\Customer\Model\CustomerFactory $customerFactory
  153. * @param array $data
  154. * @SuppressWarnings(PHPMD.ExcessiveParameterList)
  155. */
  156. public function __construct(
  157. \Magento\Framework\Stdlib\StringUtils $string,
  158. \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
  159. \Magento\ImportExport\Model\ImportFactory $importFactory,
  160. \Magento\ImportExport\Model\ResourceModel\Helper $resourceHelper,
  161. \Magento\Framework\App\ResourceConnection $resource,
  162. ProcessingErrorAggregatorInterface $errorAggregator,
  163. \Magento\Store\Model\StoreManagerInterface $storeManager,
  164. \Magento\ImportExport\Model\Export\Factory $collectionFactory,
  165. \Magento\Eav\Model\Config $eavConfig,
  166. \Magento\CustomerImportExport\Model\ResourceModel\Import\Customer\StorageFactory $storageFactory,
  167. \Magento\Customer\Model\ResourceModel\Attribute\CollectionFactory $attrCollectionFactory,
  168. \Magento\Customer\Model\CustomerFactory $customerFactory,
  169. array $data = []
  170. ) {
  171. $this->_resourceHelper = $resourceHelper;
  172. if (isset($data['attribute_collection'])) {
  173. $this->_attributeCollection = $data['attribute_collection'];
  174. unset($data['attribute_collection']);
  175. } else {
  176. $this->_attributeCollection = $attrCollectionFactory->create();
  177. $this->_attributeCollection->addSystemHiddenFilterWithPasswordHash();
  178. $data['attribute_collection'] = $this->_attributeCollection;
  179. }
  180. parent::__construct(
  181. $string,
  182. $scopeConfig,
  183. $importFactory,
  184. $resourceHelper,
  185. $resource,
  186. $errorAggregator,
  187. $storeManager,
  188. $collectionFactory,
  189. $eavConfig,
  190. $storageFactory,
  191. $data
  192. );
  193. $this->_specialAttributes[] = self::COLUMN_WEBSITE;
  194. $this->_specialAttributes[] = self::COLUMN_STORE;
  195. $this->_permanentAttributes[] = self::COLUMN_EMAIL;
  196. $this->_permanentAttributes[] = self::COLUMN_WEBSITE;
  197. $this->_indexValueAttributes[] = 'group_id';
  198. $this->addMessageTemplate(
  199. self::ERROR_DUPLICATE_EMAIL_SITE,
  200. __('This email is found more than once in the import file.')
  201. );
  202. $this->addMessageTemplate(
  203. self::ERROR_ROW_IS_ORPHAN,
  204. __('Orphan rows that will be skipped due default row errors')
  205. );
  206. $this->addMessageTemplate(
  207. self::ERROR_INVALID_STORE,
  208. __('Invalid value in Store column (store does not exists?)')
  209. );
  210. $this->addMessageTemplate(
  211. self::ERROR_EMAIL_SITE_NOT_FOUND,
  212. __('We can\'t find that email and website combination.')
  213. );
  214. $this->addMessageTemplate(self::ERROR_PASSWORD_LENGTH, __('Please enter a password with a valid length.'));
  215. $this->_initStores(true)->_initAttributes();
  216. $this->_customerModel = $customerFactory->create();
  217. /** @var $customerResource \Magento\Customer\Model\ResourceModel\Customer */
  218. $customerResource = $this->_customerModel->getResource();
  219. $this->_entityTable = $customerResource->getEntityTable();
  220. }
  221. /**
  222. * Update and insert data in entity table
  223. *
  224. * @param array $entitiesToCreate Rows for insert
  225. * @param array $entitiesToUpdate Rows for update
  226. * @return $this
  227. */
  228. protected function _saveCustomerEntities(array $entitiesToCreate, array $entitiesToUpdate)
  229. {
  230. if ($entitiesToCreate) {
  231. $this->_connection->insertMultiple($this->_entityTable, $entitiesToCreate);
  232. }
  233. if ($entitiesToUpdate) {
  234. $this->_connection->insertOnDuplicate(
  235. $this->_entityTable,
  236. $entitiesToUpdate,
  237. $this->getCustomerEntityFieldsToUpdate($entitiesToUpdate)
  238. );
  239. }
  240. return $this;
  241. }
  242. /**
  243. * Filter the entity that are being updated so we only change fields found in the importer file
  244. *
  245. * @param array $entitiesToUpdate
  246. * @return array
  247. */
  248. private function getCustomerEntityFieldsToUpdate(array $entitiesToUpdate): array
  249. {
  250. $firstCustomer = reset($entitiesToUpdate);
  251. $columnsToUpdate = array_keys($firstCustomer);
  252. $customerFieldsToUpdate = array_filter($this->customerFields, function ($field) use ($columnsToUpdate) {
  253. return in_array($field, $columnsToUpdate);
  254. });
  255. return $customerFieldsToUpdate;
  256. }
  257. /**
  258. * Save customer attributes.
  259. *
  260. * @param array $attributesData
  261. * @return $this
  262. */
  263. protected function _saveCustomerAttributes(array $attributesData)
  264. {
  265. foreach ($attributesData as $tableName => $data) {
  266. $tableData = [];
  267. foreach ($data as $customerId => $attributeData) {
  268. foreach ($attributeData as $attributeId => $value) {
  269. $tableData[] = [
  270. 'entity_id' => $customerId,
  271. 'attribute_id' => $attributeId,
  272. 'value' => $value,
  273. ];
  274. }
  275. }
  276. $this->_connection->insertOnDuplicate($tableName, $tableData, ['value']);
  277. }
  278. return $this;
  279. }
  280. /**
  281. * Delete list of customers
  282. *
  283. * @param array $entitiesToDelete customers id list
  284. * @return $this
  285. */
  286. protected function _deleteCustomerEntities(array $entitiesToDelete)
  287. {
  288. $condition = $this->_connection->quoteInto('entity_id IN (?)', $entitiesToDelete);
  289. $this->_connection->delete($this->_entityTable, $condition);
  290. return $this;
  291. }
  292. /**
  293. * Retrieve next customer entity id
  294. *
  295. * @return int
  296. */
  297. protected function _getNextEntityId()
  298. {
  299. if (!$this->_nextEntityId) {
  300. $this->_nextEntityId = $this->_resourceHelper->getNextAutoincrement($this->_entityTable);
  301. }
  302. return $this->_nextEntityId++;
  303. }
  304. /**
  305. * Prepare customers data for existing customers checks to perform mass validation/import efficiently.
  306. *
  307. * @param array|AbstractSource $rows
  308. *
  309. * @return void
  310. * @since 100.2.3
  311. */
  312. public function prepareCustomerData($rows): void
  313. {
  314. $customersPresent = [];
  315. foreach ($rows as $rowData) {
  316. $email = $rowData[static::COLUMN_EMAIL] ?? null;
  317. $websiteId = isset($rowData[static::COLUMN_WEBSITE])
  318. ? $this->getWebsiteId($rowData[static::COLUMN_WEBSITE]) : false;
  319. if ($email && $websiteId !== false) {
  320. $customersPresent[] = [
  321. 'email' => $email,
  322. 'website_id' => $websiteId,
  323. ];
  324. }
  325. }
  326. $this->getCustomerStorage()->prepareCustomers($customersPresent);
  327. }
  328. /**
  329. * @inheritDoc
  330. * @since 100.2.3
  331. */
  332. public function validateData()
  333. {
  334. $this->prepareCustomerData($this->getSource());
  335. return parent::validateData();
  336. }
  337. /**
  338. * Prepare customer data for update
  339. *
  340. * @param array $rowData
  341. * @return array
  342. * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  343. * @SuppressWarnings(PHPMD.NPathComplexity)
  344. */
  345. protected function _prepareDataForUpdate(array $rowData)
  346. {
  347. $multiSeparator = $this->getMultipleValueSeparator();
  348. $entitiesToCreate = [];
  349. $entitiesToUpdate = [];
  350. $attributesToSave = [];
  351. // entity table data
  352. $now = new \DateTime();
  353. if (empty($rowData['created_at'])) {
  354. $createdAt = $now;
  355. } else {
  356. $createdAt = (new \DateTime())->setTimestamp(strtotime($rowData['created_at']));
  357. }
  358. $emailInLowercase = strtolower($rowData[self::COLUMN_EMAIL]);
  359. $newCustomer = false;
  360. $entityId = $this->_getCustomerId($emailInLowercase, $rowData[self::COLUMN_WEBSITE]);
  361. if (!$entityId) {
  362. // create
  363. $newCustomer = true;
  364. $entityId = $this->_getNextEntityId();
  365. $this->_newCustomers[$emailInLowercase][$rowData[self::COLUMN_WEBSITE]] = $entityId;
  366. }
  367. // password change/set
  368. if (isset($rowData['password']) && strlen($rowData['password'])) {
  369. $rowData['password_hash'] = $this->_customerModel->hashPassword($rowData['password']);
  370. }
  371. $entityRow = ['entity_id' => $entityId];
  372. // attribute values
  373. foreach (array_intersect_key($rowData, $this->_attributes) as $attributeCode => $value) {
  374. $attributeParameters = $this->_attributes[$attributeCode];
  375. if (in_array($attributeParameters['type'], ['select', 'boolean'])) {
  376. $value = $this->getSelectAttrIdByValue($attributeParameters, $value);
  377. } elseif ('multiselect' == $attributeParameters['type']) {
  378. $ids = [];
  379. foreach (explode($multiSeparator, mb_strtolower($value)) as $subValue) {
  380. $ids[] = $this->getSelectAttrIdByValue($attributeParameters, $subValue);
  381. }
  382. $value = implode(',', $ids);
  383. } elseif ('datetime' == $attributeParameters['type'] && !empty($value)) {
  384. $value = (new \DateTime())->setTimestamp(strtotime($value));
  385. $value = $value->format(\Magento\Framework\Stdlib\DateTime::DATETIME_PHP_FORMAT);
  386. }
  387. if (!$this->_attributes[$attributeCode]['is_static']) {
  388. /** @var $attribute \Magento\Customer\Model\Attribute */
  389. $attribute = $this->_customerModel->getAttribute($attributeCode);
  390. $backendModel = $attribute->getBackendModel();
  391. if ($backendModel
  392. && $attribute->getFrontendInput() != 'select'
  393. && $attribute->getFrontendInput() != 'datetime') {
  394. $attribute->getBackend()->beforeSave($this->_customerModel->setData($attributeCode, $value));
  395. $value = $this->_customerModel->getData($attributeCode);
  396. }
  397. $attributesToSave[$attribute->getBackend()
  398. ->getTable()][$entityId][$attributeParameters['id']] = $value;
  399. // restore 'backend_model' to avoid default setting
  400. $attribute->setBackendModel($backendModel);
  401. } else {
  402. $entityRow[$attributeCode] = $value;
  403. }
  404. }
  405. if ($newCustomer) {
  406. // create
  407. $entityRow['group_id'] = empty($rowData['group_id']) ? self::DEFAULT_GROUP_ID : $rowData['group_id'];
  408. $entityRow['store_id'] = empty($rowData[self::COLUMN_STORE])
  409. ? \Magento\Store\Model\Store::DEFAULT_STORE_ID : $this->_storeCodeToId[$rowData[self::COLUMN_STORE]];
  410. $entityRow['created_at'] = $createdAt->format(\Magento\Framework\Stdlib\DateTime::DATETIME_PHP_FORMAT);
  411. $entityRow['updated_at'] = $now->format(\Magento\Framework\Stdlib\DateTime::DATETIME_PHP_FORMAT);
  412. $entityRow['website_id'] = $this->_websiteCodeToId[$rowData[self::COLUMN_WEBSITE]];
  413. $entityRow['email'] = $emailInLowercase;
  414. $entityRow['is_active'] = 1;
  415. $entitiesToCreate[] = $entityRow;
  416. } else {
  417. // edit
  418. $entityRow['updated_at'] = $now->format(\Magento\Framework\Stdlib\DateTime::DATETIME_PHP_FORMAT);
  419. if (!empty($rowData[self::COLUMN_STORE])) {
  420. $entityRow['store_id'] = $this->_storeCodeToId[$rowData[self::COLUMN_STORE]];
  421. }
  422. $entitiesToUpdate[] = $entityRow;
  423. }
  424. return [
  425. self::ENTITIES_TO_CREATE_KEY => $entitiesToCreate,
  426. self::ENTITIES_TO_UPDATE_KEY => $entitiesToUpdate,
  427. self::ATTRIBUTES_TO_SAVE_KEY => $attributesToSave
  428. ];
  429. }
  430. /**
  431. * Import data rows
  432. *
  433. * @return bool
  434. * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  435. * @SuppressWarnings(PHPMD.NPathComplexity)
  436. */
  437. protected function _importData()
  438. {
  439. while ($bunch = $this->_dataSourceModel->getNextBunch()) {
  440. $this->prepareCustomerData($bunch);
  441. $entitiesToCreate = [];
  442. $entitiesToUpdate = [];
  443. $entitiesToDelete = [];
  444. $attributesToSave = [];
  445. foreach ($bunch as $rowNumber => $rowData) {
  446. if (!$this->validateRow($rowData, $rowNumber)) {
  447. continue;
  448. }
  449. if ($this->getErrorAggregator()->hasToBeTerminated()) {
  450. $this->getErrorAggregator()->addRowToSkip($rowNumber);
  451. continue;
  452. }
  453. if ($this->getBehavior($rowData) == \Magento\ImportExport\Model\Import::BEHAVIOR_DELETE) {
  454. $entitiesToDelete[] = $this->_getCustomerId(
  455. $rowData[self::COLUMN_EMAIL],
  456. $rowData[self::COLUMN_WEBSITE]
  457. );
  458. } elseif ($this->getBehavior($rowData) == \Magento\ImportExport\Model\Import::BEHAVIOR_ADD_UPDATE) {
  459. $processedData = $this->_prepareDataForUpdate($rowData);
  460. $entitiesToCreate = array_merge($entitiesToCreate, $processedData[self::ENTITIES_TO_CREATE_KEY]);
  461. $entitiesToUpdate = array_merge($entitiesToUpdate, $processedData[self::ENTITIES_TO_UPDATE_KEY]);
  462. foreach ($processedData[self::ATTRIBUTES_TO_SAVE_KEY] as $tableName => $customerAttributes) {
  463. if (!isset($attributesToSave[$tableName])) {
  464. $attributesToSave[$tableName] = [];
  465. }
  466. $attributesToSave[$tableName] = array_diff_key(
  467. $attributesToSave[$tableName],
  468. $customerAttributes
  469. ) + $customerAttributes;
  470. }
  471. }
  472. }
  473. $this->updateItemsCounterStats($entitiesToCreate, $entitiesToUpdate, $entitiesToDelete);
  474. /**
  475. * Save prepared data
  476. */
  477. if ($entitiesToCreate || $entitiesToUpdate) {
  478. $this->_saveCustomerEntities($entitiesToCreate, $entitiesToUpdate);
  479. }
  480. if ($attributesToSave) {
  481. $this->_saveCustomerAttributes($attributesToSave);
  482. }
  483. if ($entitiesToDelete) {
  484. $this->_deleteCustomerEntities($entitiesToDelete);
  485. }
  486. }
  487. return true;
  488. }
  489. /**
  490. * EAV entity type code getter
  491. *
  492. * @return string
  493. */
  494. public function getEntityTypeCode()
  495. {
  496. return $this->_attributeCollection->getEntityTypeCode();
  497. }
  498. /**
  499. * Validate row data for add/update behaviour
  500. *
  501. * @param array $rowData
  502. * @param int $rowNumber
  503. * @return void
  504. * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  505. * @SuppressWarnings(PHPMD.NPathComplexity)
  506. */
  507. protected function _validateRowForUpdate(array $rowData, $rowNumber)
  508. {
  509. if ($this->_checkUniqueKey($rowData, $rowNumber)) {
  510. $email = strtolower($rowData[self::COLUMN_EMAIL]);
  511. $website = $rowData[self::COLUMN_WEBSITE];
  512. if (isset($this->_newCustomers[strtolower($rowData[self::COLUMN_EMAIL])][$website])) {
  513. $this->addRowError(self::ERROR_DUPLICATE_EMAIL_SITE, $rowNumber);
  514. }
  515. $this->_newCustomers[$email][$website] = false;
  516. if (!empty($rowData[self::COLUMN_STORE]) && !isset($this->_storeCodeToId[$rowData[self::COLUMN_STORE]])) {
  517. $this->addRowError(self::ERROR_INVALID_STORE, $rowNumber);
  518. }
  519. // check password
  520. if (isset(
  521. $rowData['password']
  522. ) && strlen(
  523. $rowData['password']
  524. ) && $this->string->strlen(
  525. $rowData['password']
  526. ) < self::MIN_PASSWORD_LENGTH
  527. ) {
  528. $this->addRowError(self::ERROR_PASSWORD_LENGTH, $rowNumber);
  529. }
  530. // check simple attributes
  531. foreach ($this->_attributes as $attributeCode => $attributeParams) {
  532. if (in_array($attributeCode, $this->_ignoredAttributes)) {
  533. continue;
  534. }
  535. $isFieldRequired = $attributeParams['is_required'];
  536. $isFieldNotSetAndCustomerDoesNotExist =
  537. !isset($rowData[$attributeCode]) && !$this->_getCustomerId($email, $website);
  538. $isFieldSetAndTrimmedValueIsEmpty
  539. = isset($rowData[$attributeCode]) && '' === trim($rowData[$attributeCode]);
  540. if ($isFieldRequired && ($isFieldNotSetAndCustomerDoesNotExist || $isFieldSetAndTrimmedValueIsEmpty)) {
  541. $this->addRowError(self::ERROR_VALUE_IS_REQUIRED, $rowNumber, $attributeCode);
  542. continue;
  543. }
  544. if (isset($rowData[$attributeCode]) && strlen($rowData[$attributeCode])) {
  545. $this->isAttributeValid(
  546. $attributeCode,
  547. $attributeParams,
  548. $rowData,
  549. $rowNumber,
  550. isset($this->_parameters[Import::FIELD_FIELD_MULTIPLE_VALUE_SEPARATOR])
  551. ? $this->_parameters[Import::FIELD_FIELD_MULTIPLE_VALUE_SEPARATOR]
  552. : Import::DEFAULT_GLOBAL_MULTI_VALUE_SEPARATOR
  553. );
  554. }
  555. }
  556. }
  557. }
  558. /**
  559. * Validate row data for delete behaviour
  560. *
  561. * @param array $rowData
  562. * @param int $rowNumber
  563. * @return void
  564. */
  565. protected function _validateRowForDelete(array $rowData, $rowNumber)
  566. {
  567. if ($this->_checkUniqueKey($rowData, $rowNumber)) {
  568. if (!$this->_getCustomerId($rowData[self::COLUMN_EMAIL], $rowData[self::COLUMN_WEBSITE])) {
  569. $this->addRowError(self::ERROR_CUSTOMER_NOT_FOUND, $rowNumber);
  570. }
  571. }
  572. }
  573. /**
  574. * Entity table name getter
  575. *
  576. * @return string
  577. */
  578. public function getEntityTable()
  579. {
  580. return $this->_entityTable;
  581. }
  582. /**
  583. * @inheritDoc
  584. */
  585. public function getValidColumnNames()
  586. {
  587. return array_unique(
  588. array_merge(
  589. $this->validColumnNames,
  590. $this->customerFields
  591. )
  592. );
  593. }
  594. }