command->error('File CSV tidak ditemukan.'); return; } if (($handle = fopen($filePath, 'r')) === false) { Log::error('Gagal membuka file CSV: ' . $filePath); $this->command->error('Gagal membuka file CSV.'); return; } $header = fgetcsv($handle, 0, '~'); $rows = []; $batchSize = 100; // Ukuran batch $branchCache = []; $debitureCache = []; $hubunganPemilikCache = []; $provinceCache = []; $cityCache = []; $districtCache = []; $subdistrictCache = []; while (($data = fgetcsv($handle, 0, '~')) !== false) { if (count($data) != count($header)) { Log::warning('Baris CSV memiliki jumlah kolom yang tidak sesuai: ' . json_encode($data)); continue; } $rows[] = array_combine($header, $data); if (count($rows) >= $batchSize) { $this->processBatch($rows, $branchCache, $debitureCache, $hubunganPemilikCache, $provinceCache, $cityCache, $districtCache, $subdistrictCache); $rows = []; } } // print_r($rows); if (!empty($rows)) { $this->processBatch($rows, $branchCache, $debitureCache, $hubunganPemilikCache, $provinceCache, $cityCache, $districtCache, $subdistrictCache); } fclose($handle); $this->command->info('Data permohonan berhasil dimigrasikan.'); } private function processBatch(array $rows, array &$branchCache, array &$debitureCache, array &$hubunganPemilikCache, array &$provinceCache, array &$cityCache, array &$districtCache, array &$subdistrictCache) { foreach ($rows as $index => $row) { $debitureId = $this->getDebiturId($row['mig_kd_debitur_seq'], $debitureCache); if (!$debitureId) { Log::warning('Debitur tidak ditemukan untuk kode: ' . $row['mig_kd_debitur_seq']); continue; } $hubunganPemilik = $this->getHubunganPemilikId($row['mig_hubungan_pemilik_jaminan'], $hubunganPemilikCache); $proviceCode = $this->getProvinceCode($row['mig_province_name'], $provinceCache); $cityCode = $this->getCityCode($row['mig_city_name'], $cityCache); $districtCode = $this->getDistrictCode($row['mig_district_name'], $districtCache); $subdistrictCode = $this->getSubdistrictCode($row['mig_village_name'], $subdistrictCache, $districtCache); PemilikJaminan::create([ 'debiture_id' => $debitureId, 'hubungan_pemilik_jaminan_id' => $hubunganPemilik, 'name' => $row['name'], 'detail_sertifikat' => null, 'npwp' => null, 'nomor_id' => null, 'email' => null, 'phone' => null, 'province_code' => $proviceCode, 'city_code' => $cityCode, 'district_code' => $districtCode, 'village_code' => $subdistrictCode['code'], 'postal_code' => $subdistrictCode['postal_code'], 'address' => $row['address'], 'created_at' => $this->parseTimestamp($row['created_at']), 'updated_at' => $this->parseTimestamp($row['updated_at']), 'mig_kd_debitur_seq' => $row['mig_kd_debitur_seq'], 'processed_at' => now(), 'is_mig' => 1 ]); $this->command->info('Proses data Pemilik Jaminan ' . $row['name'] . ' (' . ($index + 1) . '/' . count($rows) . ')'); } } private function getDebiturId(string $code, array &$cache): ?int { if (isset($cache[$code])) { return $cache[$code]; } $debitur = Debiture::where('mig_kd_debitur_seq', $code)->first(); if ($debitur) { $cache[$code] = $debitur->id; return $debitur->id; } return null; } private function getHubunganPemilikId(string $name, array &$cache): ?int { // Normalisasi nama $normalizedName = strtolower(trim($name)); // Cek cache untuk menghindari query berulang if (isset($cache[$normalizedName])) { return $cache[$normalizedName]; } // Query database dengan pengamanan tambahan $hubunganPemilik = HubunganPemilikJaminan::whereRaw('LOWER(name) = ?', [$normalizedName]) ->whereNull('deleted_at') // Tambahkan ini jika Anda menggunakan soft deletes ->first(); // Jika data ditemukan, simpan dalam cache if ($hubunganPemilik) { $cache[$normalizedName] = $hubunganPemilik->id; return $hubunganPemilik->id; } // Default jika data tidak ditemukan $cache[$normalizedName] = 1; // Cache nilai default untuk menghindari query berulang return 1; } private function getProvinceCode(string $name, array &$cache): ?string { $normalizedName = strtolower($name); if (isset($cache[$normalizedName])) { return $cache[$normalizedName]; } $province = Province::whereRaw('LOWER(name) = ?', [strtolower($name)])->first(); if ($province) { $cache[$normalizedName] = $province->code; return $province->code; } return null; } private function getCityCode(string $name, array &$cache): ?string { $normalizedName = strtolower($name); if (isset($cache[$normalizedName])) { return $cache[$normalizedName]; } $city = City::whereRaw('LOWER(name) = ?', [strtolower($name)])->first(); if ($city) { $cache[$normalizedName] = $city->code; return $city->code; } return null; } private function getDistrictCode(string $name, array &$cache): ?string { $normalizedName = strtolower($name); if (isset($cache[$normalizedName])) { return $cache[$normalizedName]; } $district = District::whereRaw('LOWER(name) = ?', [strtolower($name)])->first(); if ($district) { $cache[$normalizedName] = $district->code; return $district->code; } return null; } private function getSubdistrictCode(string $name, array &$cache, array &$districtCache): ?array { $normalizedName = strtolower($name); // Pastikan cache menyimpan array, bukan hanya kode if (isset($cache[$normalizedName])) { return $cache[$normalizedName]; } // Ambil subdistrict dari database $subdistrict = Village::whereRaw('LOWER(name) = ?', [$normalizedName])->first(); // Jika ditemukan, simpan ke dalam cache sebagai array lengkap if ($subdistrict) { $cache[$normalizedName] = [ 'code' => $subdistrict->code, 'postal_code' => $subdistrict->postal_code ]; return $cache[$normalizedName]; } // Jika tidak ditemukan, kembalikan null return [ 'code' => null, 'postal_code' => null ]; } private function parseDate(?string $date): ?string { try { return $date ? \Carbon\Carbon::createFromFormat('Y-m-d', $date)->toDateString() : null; } catch (\Exception $e) { Log::error('Gagal memparsing tanggal: ' . $date); return null; } } private function parseTimestamp(?string $timestamp): ?string { try { return $timestamp ? \Carbon\Carbon::createFromFormat('Y-m-d H:i:s', $timestamp)->toDateTimeString() : null; } catch (\Exception $e) { Log::error('Gagal memparsing timestamp: ' . $timestamp); return null; } } }