Csv.php 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Framework\Setup\Declaration\Schema\FileSystem;
  7. use Magento\Framework\App\Filesystem\DirectoryList;
  8. /**
  9. * CSV file operations wrapper.
  10. */
  11. class Csv implements \Magento\Framework\Setup\Declaration\Schema\DataSavior\DumpAccessorInterface
  12. {
  13. /**
  14. * Folder where will be persisted all csv dumps
  15. */
  16. const DUMP_FOLDER = 'declarative_dumps_csv';
  17. /**
  18. * @var int
  19. */
  20. private $baseBatchSize;
  21. /**
  22. * @var DirectoryList
  23. */
  24. private $directoryList;
  25. /**
  26. * @var \Magento\Framework\Filesystem\Driver\File
  27. */
  28. private $fileDriver;
  29. /**
  30. * Csv constructor.
  31. * @param DirectoryList $directoryList
  32. * @param \Magento\Framework\Filesystem\Driver\File $fileDriver
  33. * @param int $baseBatchSize
  34. */
  35. public function __construct(
  36. DirectoryList $directoryList,
  37. \Magento\Framework\Filesystem\Driver\File $fileDriver,
  38. $baseBatchSize = 15000
  39. ) {
  40. $this->baseBatchSize = $baseBatchSize;
  41. $this->directoryList = $directoryList;
  42. $this->fileDriver = $fileDriver;
  43. }
  44. /**
  45. * Save to csv data with batches.
  46. *
  47. * @param string $file
  48. * @param array $data
  49. * @return $this
  50. */
  51. public function save($file, array $data)
  52. {
  53. $file = $this->prepareFile($file);
  54. if (!count($data) || !$file) {
  55. return $this;
  56. }
  57. if (!file_exists($file)) {
  58. array_unshift($data, array_keys($data[0]));
  59. }
  60. $fh = fopen($file, 'a');
  61. foreach ($data as $dataRow) {
  62. fputcsv($fh, $dataRow);
  63. }
  64. fclose($fh);
  65. return $this;
  66. }
  67. /**
  68. * Prepare CSV file name
  69. *
  70. * @param string $file
  71. * @return string | bool
  72. */
  73. private function prepareFile($file)
  74. {
  75. $absolutePath = $this->directoryList->getPath(DirectoryList::VAR_DIR);
  76. if (!$this->fileDriver->isWritable($absolutePath)) {
  77. return false;
  78. }
  79. $dumpsPath = $absolutePath . DIRECTORY_SEPARATOR . self::DUMP_FOLDER;
  80. $this->ensureDirExists($dumpsPath);
  81. $filePath = $dumpsPath . DIRECTORY_SEPARATOR . $file . '.csv';
  82. return $filePath;
  83. }
  84. /**
  85. * Create directory if not exists
  86. *
  87. * @param string $dir
  88. */
  89. private function ensureDirExists($dir)
  90. {
  91. if (!$this->fileDriver->isExists($dir)) {
  92. $this->fileDriver->createDirectory($dir);
  93. }
  94. }
  95. /**
  96. * File read generator.
  97. *
  98. * This generator allows to load to memory only batch, with which we need to work at the moment
  99. *
  100. * @param string $file
  101. * @return \Generator
  102. */
  103. public function read($file)
  104. {
  105. $file = $this->prepareFile($file);
  106. if (!$this->fileDriver->isReadable($file)) {
  107. return [];
  108. }
  109. $data = [];
  110. $iterator = 0;
  111. $fh = fopen($file, 'r');
  112. $headers = fgetcsv($fh);
  113. $rowData = fgetcsv($fh);
  114. while ($rowData) {
  115. if ($iterator++ > $this->baseBatchSize) {
  116. $iterator = 0;
  117. $finalData = $data;
  118. $data = [];
  119. yield $this->processCsvData($finalData, $headers);
  120. }
  121. $data[] = $rowData;
  122. $rowData = fgetcsv($fh);
  123. }
  124. fclose($fh);
  125. yield $this->processCsvData($data, $headers);
  126. }
  127. /**
  128. * @param array $csvData
  129. * @param array $headers
  130. * @return array
  131. */
  132. private function processCsvData(array $csvData, array $headers)
  133. {
  134. $result = [];
  135. foreach ($csvData as $rowIndex => $csvRow) {
  136. foreach ($csvRow as $index => $item) {
  137. $result[$rowIndex][$headers[$index]] = $item;
  138. }
  139. }
  140. return $result;
  141. }
  142. /**
  143. * @inheritdoc
  144. */
  145. public function destruct($resource)
  146. {
  147. $file = $this->prepareFile($resource);
  148. if ($this->fileDriver->isExists($file)) {
  149. $this->fileDriver->deleteFile($file);
  150. }
  151. }
  152. }