ImportGeoNames.php 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. declare(strict_types=1);
  7. namespace Magento\InventoryDistanceBasedSourceSelection\Model;
  8. use Magento\Framework\App\Filesystem\DirectoryList;
  9. use Magento\Framework\Exception\LocalizedException;
  10. use Magento\Framework\Filesystem;
  11. use Magento\Framework\Filesystem\Io\File;
  12. use Magento\Framework\HTTP\ClientInterface;
  13. use Magento\InventoryDistanceBasedSourceSelection\Model\ResourceModel\UpdateGeoNames;
  14. /**
  15. * Import geonames
  16. */
  17. class ImportGeoNames
  18. {
  19. /**
  20. * @var ClientInterface
  21. */
  22. private $client;
  23. /**
  24. * @var File
  25. */
  26. private $file;
  27. /**
  28. * @var Filesystem
  29. */
  30. private $filesystem;
  31. /**
  32. * @var UpdateGeoNames
  33. */
  34. private $updateGeoNames;
  35. /**
  36. * @var string
  37. */
  38. private $geoNamesBaseUrl;
  39. /**
  40. * ImportGeoNames constructor.
  41. *
  42. * @param ClientInterface $client
  43. * @param Filesystem $filesystem
  44. * @param File $file
  45. * @param UpdateGeoNames $updateGeoNames
  46. * @param string $geoNamesBaseUrl
  47. */
  48. public function __construct(
  49. ClientInterface $client,
  50. Filesystem $filesystem,
  51. File $file,
  52. UpdateGeoNames $updateGeoNames,
  53. string $geoNamesBaseUrl
  54. ) {
  55. $this->client = $client;
  56. $this->file = $file;
  57. $this->filesystem = $filesystem;
  58. $this->updateGeoNames = $updateGeoNames;
  59. $this->geoNamesBaseUrl = $geoNamesBaseUrl;
  60. }
  61. /**
  62. * Download a country
  63. *
  64. * @param string $countryCode
  65. * @return string
  66. * @throws \Magento\Framework\Exception\FileSystemException
  67. */
  68. private function downloadCountry(string $countryCode): string
  69. {
  70. $countryZipFile = $this->geoNamesBaseUrl . $countryCode. '.zip';
  71. $this->client->get($countryZipFile);
  72. $varDir = $this->filesystem->getDirectoryWrite(DirectoryList::VAR_DIR);
  73. $exportPath = $varDir->getAbsolutePath('geonames');
  74. $this->file->mkdir($exportPath, 0770, true);
  75. $destinationFile = $exportPath . '/' . $countryCode. '.zip';
  76. $this->file->write($destinationFile, $this->client->getBody());
  77. return $destinationFile;
  78. }
  79. /**
  80. * In memory extract ZIP file to string
  81. *
  82. * @param string $zipFile
  83. * @param string $countryCode
  84. * @return string
  85. * @throws LocalizedException
  86. */
  87. private function unpackZipFile(string $zipFile, string $countryCode): string
  88. {
  89. $zipArchive = new \ZipArchive();
  90. $res = $zipArchive->open($zipFile);
  91. if ($res !== true) {
  92. throw new LocalizedException(__('Cannot download country'));
  93. }
  94. $resource = $zipArchive->getStream($countryCode . '.txt');
  95. $contents = '';
  96. while (!feof($resource)) {
  97. $contents .= fread($resource, 1024);
  98. }
  99. return $contents;
  100. }
  101. /**
  102. * Import TSV file
  103. *
  104. * @param string $tsvContent
  105. * @param string $countryCode
  106. * @return int
  107. */
  108. private function importTsv(string $tsvContent, string $countryCode): int
  109. {
  110. $lines = preg_split('/[\r\n]+/', $tsvContent);
  111. $geoNames = [];
  112. foreach ($lines as $line) {
  113. $parts = explode("\t", $line);
  114. if (count($parts) < 10) {
  115. continue;
  116. }
  117. $geoNames[] = [
  118. 'country_code' => $countryCode,
  119. 'postcode' => $parts[1],
  120. 'city' => $parts[2],
  121. 'region' => $parts[3],
  122. 'province' => $parts[6],
  123. 'latitude' => (float) $parts[9],
  124. 'longitude' => (float) $parts[10],
  125. ];
  126. }
  127. $this->updateGeoNames->execute($geoNames, $countryCode);
  128. return count($geoNames);
  129. }
  130. /**
  131. * Import geonames and return the amount of items
  132. *
  133. * @param string $countryCode
  134. * @return int
  135. * @throws LocalizedException
  136. * @throws \Magento\Framework\Exception\FileSystemException
  137. */
  138. public function execute(string $countryCode): int
  139. {
  140. $countryCode = strtoupper(preg_replace('/\W/', '', $countryCode));
  141. if (!$countryCode) {
  142. throw new LocalizedException(__('Undefined country code'));
  143. }
  144. $zipFile = $this->downloadCountry($countryCode);
  145. $tsvFile = $this->unpackZipFile($zipFile, $countryCode);
  146. return $this->importTsv($tsvFile, $countryCode);
  147. }
  148. }