info('Starting optimized journalist migration with document support...'); $legacyConn = DB::connection('mysql_second'); $query = $legacyConn->table('journalists'); $totalCount = $query->count(); if ($totalCount === 0) { $this->warn('No journalists found in legacy database.'); return; } $this->info("Found {$totalCount} legacy journalist records."); // Pre-cache migrated IDs $this->migratedIds = DB::table('media') ->where('model_type', Journalist::class) ->where('collection_name', 'journalists') ->pluck('model_id') ->flip() ->all(); $query->orderBy('id')->chunk(50, function ($chunk) { foreach ($chunk as $legacy) { $this->processJournalist($legacy); } }); $this->newLine(); $this->info('Journalist migration completed successfully!'); } /** * Process a single legacy journalist record. */ private function processJournalist($legacy): void { $idText = "[#{$legacy->id}]"; $idOutput = $legacy->deleted_at ? "{$idText}" : "{$idText}"; $this->output->write("{$idOutput} Processing: ".Str::limit($legacy->name, 40).'... '); try { // Find corresponding partner media $partnerMedia = DB::table('partner_media')->where('id', $legacy->media)->first(); if (! $partnerMedia) { $this->output->writeln('OUTLET NOT FOUND'); return; } // 1. Update/Insert Journalist DB::table('journalists')->updateOrInsert( ['id' => $legacy->id], [ 'partner_media_id' => $partnerMedia->id, 'name' => Str::limit($legacy->name, 100), 'email' => Str::limit($legacy->email, 254), 'phone_number' => Str::limit($legacy->phone, 20), 'press_card' => Str::limit($legacy->press_card, 100), 'ukw_certificate' => Str::limit($legacy->certificate, 100), 'created_at' => $legacy->created_at ?? now(), 'updated_at' => $legacy->updated_at ?? now(), 'deleted_at' => $legacy->deleted_at, ] ); // 2. Media Documents Migration (Skip if already has media) if (isset($this->migratedIds[$legacy->id])) { $this->output->writeln('DONE (SKIP DOCS)'); return; } $journalist = Journalist::withTrashed()->find($legacy->id); if ($journalist) { $this->migrateJournalistDocuments($journalist, $legacy); } $this->output->writeln('DONE + DOCS'); } catch (\Exception $e) { $this->output->writeln('FAILED: '.$e->getMessage().''); } } /** * Migrate journalist documents from S3. */ private function migrateJournalistDocuments(Journalist $journalist, $legacy): void { $docMapping = [ 'doc_of_press_card' => 'press-card', 'doc_of_certificate' => 'ukw-certificate', ]; foreach ($docMapping as $legacyField => $docType) { $legacyPath = trim($legacy->{$legacyField} ?? ''); if (empty($legacyPath) || $legacyPath === '-' || $legacyPath === 'no-image.png') { continue; } // Path mapping: old-data/companies/ + path from db (based on legacy structure) $sourcePath = 'old-data/companies/'.$legacyPath; $this->importOneDocument($journalist, $sourcePath, $docType, $legacy); } } private function importOneDocument(Journalist $journalist, string $sourcePath, string $docType, $legacy): void { $fileName = basename($sourcePath); $legacyDir = dirname($sourcePath); // e.g. old-data/companies/subdir DB::table('media')->insert([ 'model_type' => Journalist::class, 'model_id' => $journalist->id, 'uuid' => (string) Str::uuid(), 'collection_name' => 'journalists', 'name' => pathinfo($fileName, PATHINFO_FILENAME), 'file_name' => $fileName, 'mime_type' => $this->guessMime($fileName), 'disk' => 's3', 'conversions_disk' => 's3', 'size' => 0, 'manipulations' => '[]', 'custom_properties' => json_encode([ 'feature' => 'journalists', 'date' => Carbon::parse($legacy->created_at ?? now())->toDateString(), 'doc_type' => $docType, 'legacy_dir' => $legacyDir, ]), 'generated_conversions' => '[]', 'responsive_images' => '[]', 'order_column' => 1, 'created_at' => now(), 'updated_at' => now(), ]); } private function guessMime(string $fileName): string { return match (strtolower(pathinfo($fileName, PATHINFO_EXTENSION))) { 'pdf' => 'application/pdf', 'jpg', 'jpeg' => 'image/jpeg', 'png' => 'image/png', 'doc' => 'application/msword', 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', default => 'application/octet-stream', }; } }