AbstractEntity.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\ImportExport\Model\Export;
  7. use Magento\Eav\Model\Entity\Attribute\AbstractAttribute;
  8. use Magento\ImportExport\Model\Export\Adapter\AbstractAdapter;
  9. use Magento\ImportExport\Model\Export;
  10. /**
  11. * Export entity abstract model
  12. *
  13. * @api
  14. *
  15. * @SuppressWarnings(PHPMD.TooManyFields)
  16. * @since 100.0.2
  17. */
  18. abstract class AbstractEntity
  19. {
  20. /**#@+
  21. * Attribute collection name
  22. */
  23. const ATTRIBUTE_COLLECTION_NAME = \Magento\Framework\Data\Collection::class;
  24. /**#@-*/
  25. /**#@+
  26. * XML path to page size parameter
  27. */
  28. const XML_PATH_PAGE_SIZE = '';
  29. /**#@-*/
  30. /**#@-*/
  31. protected $_storeManager;
  32. /**
  33. * Error codes with arrays of corresponding row numbers
  34. *
  35. * @var array
  36. */
  37. protected $_errors = [];
  38. /**
  39. * Error counter
  40. *
  41. * @var int
  42. */
  43. protected $_errorsCount = 0;
  44. /**
  45. * Limit of errors after which pre-processing will exit
  46. *
  47. * @var int
  48. */
  49. protected $_errorsLimit = 100;
  50. /**
  51. * Validation information about processed rows
  52. *
  53. * @var array
  54. */
  55. protected $_invalidRows = [];
  56. /**
  57. * Validation failure message template definitions
  58. *
  59. * @var array
  60. */
  61. protected $_messageTemplates = [];
  62. /**
  63. * Parameters
  64. *
  65. * @var array
  66. */
  67. protected $_parameters = [];
  68. /**
  69. * Number of entities processed by validation
  70. *
  71. * @var int
  72. */
  73. protected $_processedEntitiesCount = 0;
  74. /**
  75. * Number of rows processed by validation
  76. *
  77. * @var int
  78. */
  79. protected $_processedRowsCount = 0;
  80. /**
  81. * Source model
  82. *
  83. * @var AbstractAdapter
  84. */
  85. protected $_writer;
  86. /**
  87. * Array of pairs store ID to its code
  88. *
  89. * @var array
  90. */
  91. protected $_storeIdToCode = [];
  92. /**
  93. * Website ID-to-code
  94. *
  95. * @var array
  96. */
  97. protected $_websiteIdToCode = [];
  98. /**
  99. * Disabled attributes
  100. *
  101. * @var string[]
  102. */
  103. protected $_disabledAttributes = [];
  104. /**
  105. * Export file name
  106. *
  107. * @var string|null
  108. */
  109. protected $_fileName = null;
  110. /**
  111. * Address attributes collection
  112. *
  113. * @var \Magento\Framework\Data\Collection
  114. */
  115. protected $_attributeCollection;
  116. /**
  117. * Number of items to fetch from db in one query
  118. *
  119. * @var int
  120. */
  121. protected $_pageSize;
  122. /**
  123. * Collection by pages iterator
  124. *
  125. * @var \Magento\ImportExport\Model\ResourceModel\CollectionByPagesIterator
  126. */
  127. protected $_byPagesIterator;
  128. /**
  129. * Core store config
  130. *
  131. * @var \Magento\Framework\App\Config\ScopeConfigInterface
  132. */
  133. protected $_scopeConfig;
  134. /**
  135. * Attribute code to its values. Only attributes with options and only default store values used
  136. *
  137. * @var array
  138. */
  139. protected $_attributeCodes = null;
  140. /**
  141. * Permanent entity columns
  142. *
  143. * @var string[]
  144. */
  145. protected $_permanentAttributes = [];
  146. /**
  147. * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
  148. * @param \Magento\Store\Model\StoreManagerInterface $storeManager
  149. * @param \Magento\ImportExport\Model\Export\Factory $collectionFactory
  150. * @param \Magento\ImportExport\Model\ResourceModel\CollectionByPagesIteratorFactory $resourceColFactory
  151. * @param array $data
  152. * @SuppressWarnings(PHPMD.NPathComplexity)
  153. */
  154. public function __construct(
  155. \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
  156. \Magento\Store\Model\StoreManagerInterface $storeManager,
  157. \Magento\ImportExport\Model\Export\Factory $collectionFactory,
  158. \Magento\ImportExport\Model\ResourceModel\CollectionByPagesIteratorFactory $resourceColFactory,
  159. array $data = []
  160. ) {
  161. $this->_scopeConfig = $scopeConfig;
  162. $this->_storeManager = $storeManager;
  163. $this->_attributeCollection = isset(
  164. $data['attribute_collection']
  165. ) ? $data['attribute_collection'] : $collectionFactory->create(
  166. static::ATTRIBUTE_COLLECTION_NAME
  167. );
  168. $this->_pageSize = isset(
  169. $data['page_size']
  170. ) ? $data['page_size'] : (static::XML_PATH_PAGE_SIZE ? (int)$this->_scopeConfig->getValue(
  171. static::XML_PATH_PAGE_SIZE,
  172. \Magento\Store\Model\ScopeInterface::SCOPE_STORE
  173. ) : 0);
  174. $this->_byPagesIterator = isset(
  175. $data['collection_by_pages_iterator']
  176. ) ? $data['collection_by_pages_iterator'] : $resourceColFactory->create();
  177. }
  178. /**
  179. * Initialize stores hash
  180. *
  181. * @return $this
  182. */
  183. protected function _initStores()
  184. {
  185. /** @var $store \Magento\Store\Model\Store */
  186. foreach ($this->_storeManager->getStores(true) as $store) {
  187. $this->_storeIdToCode[$store->getId()] = $store->getCode();
  188. }
  189. ksort($this->_storeIdToCode);
  190. // to ensure that 'admin' store (ID is zero) goes first
  191. return $this;
  192. }
  193. /**
  194. * Initialize website values
  195. *
  196. * @param bool $withDefault
  197. * @return $this
  198. */
  199. protected function _initWebsites($withDefault = false)
  200. {
  201. /** @var $website \Magento\Store\Model\Website */
  202. foreach ($this->_storeManager->getWebsites($withDefault) as $website) {
  203. $this->_websiteIdToCode[$website->getId()] = $website->getCode();
  204. }
  205. return $this;
  206. }
  207. /**
  208. * Add error with corresponding current data source row number
  209. *
  210. * @param string $errorCode Error code or simply column name
  211. * @param int $errorRowNum Row number
  212. * @return $this
  213. */
  214. public function addRowError($errorCode, $errorRowNum)
  215. {
  216. $errorCode = (string)$errorCode;
  217. $this->_errors[$errorCode][] = $errorRowNum + 1;
  218. // one added for human readability
  219. $this->_invalidRows[$errorRowNum] = true;
  220. $this->_errorsCount++;
  221. return $this;
  222. }
  223. /**
  224. * Add message template for specific error code from outside
  225. *
  226. * @param string $errorCode Error code
  227. * @param string $message Message template
  228. * @return $this
  229. */
  230. public function addMessageTemplate($errorCode, $message)
  231. {
  232. $this->_messageTemplates[$errorCode] = $message;
  233. return $this;
  234. }
  235. /**
  236. * Retrieve message template
  237. *
  238. * @param string $errorCode
  239. * @return null|string
  240. */
  241. public function retrieveMessageTemplate($errorCode)
  242. {
  243. if (isset($this->_messageTemplates[$errorCode])) {
  244. return $this->_messageTemplates[$errorCode];
  245. }
  246. return null;
  247. }
  248. /**
  249. * Export process
  250. *
  251. * @return string
  252. */
  253. abstract public function export();
  254. /**
  255. * Export one item
  256. *
  257. * @param \Magento\Framework\Model\AbstractModel $item
  258. * @return void
  259. */
  260. abstract public function exportItem($item);
  261. /**
  262. * Iterate through given collection page by page and export items
  263. *
  264. * @param \Magento\Framework\Data\Collection\AbstractDb $collection
  265. * @return void
  266. */
  267. protected function _exportCollectionByPages(\Magento\Framework\Data\Collection\AbstractDb $collection)
  268. {
  269. $this->_byPagesIterator->iterate($collection, $this->_pageSize, [[$this, 'exportItem']]);
  270. }
  271. /**
  272. * Get attributes codes which are appropriate for export
  273. *
  274. * @return array
  275. */
  276. protected function _getExportAttributeCodes()
  277. {
  278. if (null === $this->_attributeCodes) {
  279. if (!empty($this->_parameters[Export::FILTER_ELEMENT_SKIP])
  280. && is_array($this->_parameters[Export::FILTER_ELEMENT_SKIP])
  281. ) {
  282. $skippedAttributes = array_flip(
  283. $this->_parameters[Export::FILTER_ELEMENT_SKIP]
  284. );
  285. } else {
  286. $skippedAttributes = [];
  287. }
  288. $attributeCodes = [];
  289. /** @var $attribute AbstractAttribute */
  290. foreach ($this->filterAttributeCollection($this->getAttributeCollection()) as $attribute) {
  291. if (!isset($skippedAttributes[$attribute->getAttributeId()])
  292. || in_array($attribute->getAttributeCode(), $this->_permanentAttributes)
  293. ) {
  294. $attributeCodes[] = $attribute->getAttributeCode();
  295. }
  296. }
  297. $this->_attributeCodes = $attributeCodes;
  298. }
  299. return $this->_attributeCodes;
  300. }
  301. /**
  302. * Entity type code getter
  303. *
  304. * @abstract
  305. * @return string
  306. */
  307. abstract public function getEntityTypeCode();
  308. /**
  309. * Get header columns
  310. *
  311. * @return array
  312. */
  313. abstract protected function _getHeaderColumns();
  314. /**
  315. * Get entity collection
  316. *
  317. * @return \Magento\Framework\Data\Collection\AbstractDb
  318. */
  319. abstract protected function _getEntityCollection();
  320. /**
  321. * Entity attributes collection getter
  322. *
  323. * @return \Magento\Framework\Data\Collection
  324. */
  325. public function getAttributeCollection()
  326. {
  327. return $this->_attributeCollection;
  328. }
  329. /**
  330. * Clean up attribute collection
  331. *
  332. * @param \Magento\Framework\Data\Collection $collection
  333. * @return \Magento\Framework\Data\Collection
  334. */
  335. public function filterAttributeCollection(\Magento\Framework\Data\Collection $collection)
  336. {
  337. /** @var $attribute \Magento\Eav\Model\Entity\Attribute\AbstractAttribute */
  338. foreach ($collection as $attribute) {
  339. if (in_array($attribute->getAttributeCode(), $this->_disabledAttributes)) {
  340. $collection->removeItemByKey($attribute->getId());
  341. }
  342. }
  343. return $collection;
  344. }
  345. /**
  346. * Returns error information
  347. *
  348. * @return array
  349. */
  350. public function getErrorMessages()
  351. {
  352. $messages = [];
  353. foreach ($this->_errors as $errorCode => $errorRows) {
  354. $message = isset(
  355. $this->_messageTemplates[$errorCode]
  356. ) ? __(
  357. $this->_messageTemplates[$errorCode]
  358. ) : __(
  359. 'Please correct the value for "%1" column.',
  360. $errorCode
  361. );
  362. $message = (string)$message;
  363. $messages[$message] = $errorRows;
  364. }
  365. return $messages;
  366. }
  367. /**
  368. * Returns error counter value
  369. *
  370. * @return int
  371. */
  372. public function getErrorsCount()
  373. {
  374. return $this->_errorsCount;
  375. }
  376. /**
  377. * Returns invalid rows count
  378. *
  379. * @return int
  380. */
  381. public function getInvalidRowsCount()
  382. {
  383. return count($this->_invalidRows);
  384. }
  385. /**
  386. * Returns number of checked entities
  387. *
  388. * @return int
  389. */
  390. public function getProcessedEntitiesCount()
  391. {
  392. return $this->_processedEntitiesCount;
  393. }
  394. /**
  395. * Returns number of checked rows
  396. *
  397. * @return int
  398. */
  399. public function getProcessedRowsCount()
  400. {
  401. return $this->_processedRowsCount;
  402. }
  403. /**
  404. * Inner writer object getter
  405. *
  406. * @return AbstractAdapter
  407. * @throws \Magento\Framework\Exception\LocalizedException
  408. */
  409. public function getWriter()
  410. {
  411. if (!$this->_writer) {
  412. throw new \Magento\Framework\Exception\LocalizedException(__('Please specify the writer.'));
  413. }
  414. return $this->_writer;
  415. }
  416. /**
  417. * Set parameters
  418. *
  419. * @param string[] $parameters
  420. * @return $this
  421. */
  422. public function setParameters(array $parameters)
  423. {
  424. $this->_parameters = $parameters;
  425. return $this;
  426. }
  427. /**
  428. * Writer model setter
  429. *
  430. * @param AbstractAdapter $writer
  431. * @return $this
  432. */
  433. public function setWriter(AbstractAdapter $writer)
  434. {
  435. $this->_writer = $writer;
  436. return $this;
  437. }
  438. /**
  439. * Set export file name
  440. *
  441. * @param null|string $fileName
  442. * @return void
  443. */
  444. public function setFileName($fileName)
  445. {
  446. $this->_fileName = $fileName;
  447. }
  448. /**
  449. * Get export file name
  450. *
  451. * @return null|string
  452. */
  453. public function getFileName()
  454. {
  455. return $this->_fileName;
  456. }
  457. /**
  458. * Retrieve list of disabled attributes codes
  459. *
  460. * @return string[]
  461. */
  462. public function getDisabledAttributes()
  463. {
  464. return $this->_disabledAttributes;
  465. }
  466. }