2026-03-17 12:50:26 +09:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
namespace App\Console\Commands;
|
|
|
|
|
|
2026-03-19 19:54:23 +09:00
|
|
|
use App\Models\BendingItem;
|
2026-03-17 12:50:26 +09:00
|
|
|
use App\Models\Commons\File;
|
|
|
|
|
use Illuminate\Console\Command;
|
|
|
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
|
use Illuminate\Support\Facades\Storage;
|
|
|
|
|
|
|
|
|
|
/**
|
2026-03-19 19:54:23 +09:00
|
|
|
* 레거시 이미지 → R2 업로드 + bending_items 연결
|
2026-03-17 12:50:26 +09:00
|
|
|
*
|
2026-03-19 19:54:23 +09:00
|
|
|
* 실행: php artisan bending:import-images [--dry-run] [--tenant_id=287]
|
2026-03-17 12:50:26 +09:00
|
|
|
*/
|
|
|
|
|
class BendingImportImages extends Command
|
|
|
|
|
{
|
|
|
|
|
protected $signature = 'bending:import-images
|
2026-03-19 19:54:23 +09:00
|
|
|
{--tenant_id=287 : 테넌트 ID}
|
|
|
|
|
{--dry-run : 미리보기}
|
|
|
|
|
{--legacy-path=/home/kkk/sam/5130/bending/img : 레거시 이미지 경로}';
|
2026-03-17 12:50:26 +09:00
|
|
|
|
2026-03-19 19:54:23 +09:00
|
|
|
protected $description = '레거시 절곡품 이미지 → R2 업로드 + bending_items 연결';
|
2026-03-17 12:50:26 +09:00
|
|
|
|
|
|
|
|
public function handle(): int
|
|
|
|
|
{
|
|
|
|
|
$tenantId = (int) $this->option('tenant_id');
|
|
|
|
|
$dryRun = $this->option('dry-run');
|
2026-03-19 19:54:23 +09:00
|
|
|
$legacyPath = $this->option('legacy-path');
|
2026-03-17 12:50:26 +09:00
|
|
|
|
2026-03-19 19:54:23 +09:00
|
|
|
$items = BendingItem::where('tenant_id', $tenantId)
|
|
|
|
|
->whereNotNull('legacy_bending_id')
|
|
|
|
|
->get();
|
2026-03-17 12:50:26 +09:00
|
|
|
|
2026-03-19 19:54:23 +09:00
|
|
|
$chandjMap = DB::connection('chandj')->table('bending')
|
2026-03-17 12:50:26 +09:00
|
|
|
->whereNotNull('imgdata')
|
|
|
|
|
->where('imgdata', '!=', '')
|
|
|
|
|
->pluck('imgdata', 'num');
|
|
|
|
|
|
2026-03-19 19:54:23 +09:00
|
|
|
$this->info("bending_items: {$items->count()}건 / chandj imgdata: {$chandjMap->count()}건");
|
2026-03-17 12:50:26 +09:00
|
|
|
|
2026-03-19 19:54:23 +09:00
|
|
|
$uploaded = 0;
|
|
|
|
|
$skipped = 0;
|
|
|
|
|
$notFound = 0;
|
|
|
|
|
$errors = 0;
|
2026-03-17 12:50:26 +09:00
|
|
|
|
2026-03-19 19:54:23 +09:00
|
|
|
foreach ($items as $bi) {
|
|
|
|
|
$imgFile = $chandjMap[$bi->legacy_bending_id] ?? null;
|
|
|
|
|
if (! $imgFile) {
|
|
|
|
|
$skipped++;
|
2026-03-17 12:50:26 +09:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-19 19:54:23 +09:00
|
|
|
$filePath = "{$legacyPath}/{$imgFile}";
|
|
|
|
|
if (! file_exists($filePath)) {
|
|
|
|
|
$this->warn(" ⚠️ 파일 없음: {$imgFile} (#{$bi->legacy_bending_id})");
|
|
|
|
|
$notFound++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$existing = File::where('document_type', 'bending_item')
|
|
|
|
|
->where('document_id', $bi->id)
|
2026-03-17 12:50:26 +09:00
|
|
|
->where('field_key', 'bending_diagram')
|
|
|
|
|
->whereNull('deleted_at')
|
|
|
|
|
->first();
|
|
|
|
|
|
2026-03-19 19:54:23 +09:00
|
|
|
if ($existing) {
|
|
|
|
|
$skipped++;
|
2026-03-17 12:50:26 +09:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($dryRun) {
|
2026-03-19 19:54:23 +09:00
|
|
|
$this->line(" [DRY] #{$bi->legacy_bending_id} → {$bi->id} ({$bi->item_name}) ← {$imgFile}");
|
|
|
|
|
$uploaded++;
|
2026-03-17 12:50:26 +09:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
2026-03-19 19:54:23 +09:00
|
|
|
$extension = pathinfo($imgFile, PATHINFO_EXTENSION);
|
|
|
|
|
$storedName = bin2hex(random_bytes(8)) . '.' . $extension;
|
|
|
|
|
$directory = sprintf('%d/bending/%s/%s', $tenantId, date('Y'), date('m'));
|
|
|
|
|
$r2Path = $directory . '/' . $storedName;
|
2026-03-17 12:50:26 +09:00
|
|
|
|
2026-03-19 19:54:23 +09:00
|
|
|
Storage::disk('r2')->put($r2Path, file_get_contents($filePath));
|
2026-03-17 12:50:26 +09:00
|
|
|
|
2026-03-19 19:54:23 +09:00
|
|
|
File::create([
|
2026-03-17 12:50:26 +09:00
|
|
|
'tenant_id' => $tenantId,
|
2026-03-19 19:54:23 +09:00
|
|
|
'display_name' => $imgFile,
|
2026-03-17 12:50:26 +09:00
|
|
|
'stored_name' => $storedName,
|
2026-03-19 19:54:23 +09:00
|
|
|
'file_path' => $r2Path,
|
|
|
|
|
'file_size' => filesize($filePath),
|
|
|
|
|
'mime_type' => mime_content_type($filePath),
|
2026-03-17 12:50:26 +09:00
|
|
|
'file_type' => 'image',
|
|
|
|
|
'field_key' => 'bending_diagram',
|
2026-03-19 19:54:23 +09:00
|
|
|
'document_id' => $bi->id,
|
|
|
|
|
'document_type' => 'bending_item',
|
2026-03-17 12:50:26 +09:00
|
|
|
'is_temp' => false,
|
|
|
|
|
'uploaded_by' => 1,
|
|
|
|
|
'created_by' => 1,
|
|
|
|
|
]);
|
|
|
|
|
|
2026-03-19 19:54:23 +09:00
|
|
|
$this->line(" ✅ #{$bi->legacy_bending_id} → {$bi->id} ({$bi->item_name}) ← {$imgFile}");
|
|
|
|
|
$uploaded++;
|
|
|
|
|
} catch (\Throwable $e) {
|
|
|
|
|
$this->error(" ❌ #{$bi->legacy_bending_id}: {$e->getMessage()}");
|
|
|
|
|
$errors++;
|
2026-03-17 12:50:26 +09:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->newLine();
|
2026-03-19 19:54:23 +09:00
|
|
|
$this->info("완료: 업로드 {$uploaded}, 스킵 {$skipped}, 파일없음 {$notFound}, 오류 {$errors}");
|
2026-03-17 12:50:26 +09:00
|
|
|
|
2026-03-19 19:54:23 +09:00
|
|
|
return 0;
|
2026-03-17 12:50:26 +09:00
|
|
|
}
|
|
|
|
|
}
|