ImportDistrictsService.php 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. <?php
  2. namespace App\Services\Import;
  3. use App\Models\Dictionary\District;
  4. use Exception;
  5. use Illuminate\Support\Facades\DB;
  6. use Illuminate\Support\Facades\Log;
  7. use PhpOffice\PhpSpreadsheet\IOFactory;
  8. class ImportDistrictsService
  9. {
  10. private array $logs = [];
  11. public function __construct(
  12. private readonly string $filePath,
  13. private readonly int $userId,
  14. ) {}
  15. public function handle(): array
  16. {
  17. try {
  18. $this->log("Начало импорта справочника округов");
  19. DB::beginTransaction();
  20. try {
  21. $spreadsheet = IOFactory::load($this->filePath);
  22. $sheet = $spreadsheet->getActiveSheet();
  23. $highestRow = $sheet->getHighestRow();
  24. $imported = 0;
  25. $updated = 0;
  26. $skipped = 0;
  27. for ($row = 2; $row <= $highestRow; $row++) {
  28. $id = trim($sheet->getCell('A' . $row)->getValue());
  29. $shortname = trim($sheet->getCell('B' . $row)->getValue());
  30. $name = trim($sheet->getCell('C' . $row)->getValue());
  31. // Пропускаем пустые строки
  32. if (empty($shortname) && empty($name)) {
  33. $skipped++;
  34. continue;
  35. }
  36. if (empty($name)) {
  37. $this->log("Строка {$row}: пропущена (пустое название)");
  38. $skipped++;
  39. continue;
  40. }
  41. $data = [
  42. 'shortname' => $shortname ?: mb_substr($name, 0, 10),
  43. 'name' => $name,
  44. ];
  45. // Если есть ID, ищем по нему
  46. if (!empty($id) && is_numeric($id)) {
  47. $district = District::withTrashed()->find((int) $id);
  48. if ($district) {
  49. if ($district->trashed()) {
  50. $district->restore();
  51. }
  52. $district->update($data);
  53. $updated++;
  54. continue;
  55. }
  56. }
  57. // Ищем по сокращению
  58. $district = District::withTrashed()->where('shortname', $shortname)->first();
  59. if ($district) {
  60. if ($district->trashed()) {
  61. $district->restore();
  62. }
  63. $district->update($data);
  64. $updated++;
  65. } else {
  66. District::create($data);
  67. $imported++;
  68. }
  69. }
  70. DB::commit();
  71. $this->log("Импорт округов: создано {$imported}, обновлено {$updated}, пропущено {$skipped}");
  72. return [
  73. 'success' => true,
  74. 'imported' => $imported,
  75. 'updated' => $updated,
  76. 'skipped' => $skipped,
  77. 'logs' => $this->logs,
  78. ];
  79. } catch (Exception $e) {
  80. DB::rollBack();
  81. throw $e;
  82. }
  83. } catch (Exception $e) {
  84. $this->log("ОШИБКА: " . $e->getMessage());
  85. Log::error("Ошибка импорта округов: " . $e->getMessage(), [
  86. 'trace' => $e->getTraceAsString(),
  87. ]);
  88. return [
  89. 'success' => false,
  90. 'error' => $e->getMessage(),
  91. 'logs' => $this->logs,
  92. ];
  93. }
  94. }
  95. private function log(string $message): void
  96. {
  97. $this->logs[] = '[' . date('H:i:s') . '] ' . $message;
  98. Log::info($message);
  99. }
  100. public function getLogs(): array
  101. {
  102. return $this->logs;
  103. }
  104. }