feat: files 테이블 field_key 컬럼 추가 및 file_type VARCHAR 변경
- file_type: ENUM → VARCHAR(50) 변경 (확장성 개선) - field_key: VARCHAR(100) 신규 컬럼 (비즈니스 용도 구분) - ItemsFileController: field_key 사용, file_type 자동 분류 (detectFileType) - File 모델: fillable에 field_key 추가 - ItemsService: getItemFiles()에서 field_key로 그룹핑 - rollback_items_migration: FK 제약조건 처리 수정
This commit is contained in:
@@ -51,13 +51,13 @@ public function index(int $id, Request $request)
|
|||||||
|
|
||||||
// 특정 field_key만 조회
|
// 특정 field_key만 조회
|
||||||
if ($fieldKey) {
|
if ($fieldKey) {
|
||||||
$query->where('file_type', $fieldKey);
|
$query->where('field_key', $fieldKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
$files = $query->orderBy('created_at', 'desc')->get();
|
$files = $query->orderBy('created_at', 'desc')->get();
|
||||||
|
|
||||||
// field_key별 그룹핑
|
// field_key별 그룹핑
|
||||||
$grouped = $files->groupBy('file_type')->map(function ($group) {
|
$grouped = $files->groupBy('field_key')->map(function ($group) {
|
||||||
return $group->map(fn ($file) => $this->formatFileResponse($file))->values();
|
return $group->map(fn ($file) => $this->formatFileResponse($file))->values();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -115,6 +115,10 @@ public function upload(int $id, ItemFileUploadRequest $request)
|
|||||||
// 파일 저장 (tenant 디스크)
|
// 파일 저장 (tenant 디스크)
|
||||||
Storage::disk('tenant')->putFileAs($directory, $uploadedFile, $storedName);
|
Storage::disk('tenant')->putFileAs($directory, $uploadedFile, $storedName);
|
||||||
|
|
||||||
|
// file_type 자동 분류 (MIME 타입 기반)
|
||||||
|
$mimeType = $uploadedFile->getMimeType();
|
||||||
|
$fileType = $this->detectFileType($mimeType);
|
||||||
|
|
||||||
// files 테이블에 저장
|
// files 테이블에 저장
|
||||||
$file = File::create([
|
$file = File::create([
|
||||||
'tenant_id' => $tenantId,
|
'tenant_id' => $tenantId,
|
||||||
@@ -122,8 +126,9 @@ public function upload(int $id, ItemFileUploadRequest $request)
|
|||||||
'stored_name' => $storedName,
|
'stored_name' => $storedName,
|
||||||
'file_path' => $filePath,
|
'file_path' => $filePath,
|
||||||
'file_size' => $uploadedFile->getSize(),
|
'file_size' => $uploadedFile->getSize(),
|
||||||
'mime_type' => $uploadedFile->getMimeType(),
|
'mime_type' => $mimeType,
|
||||||
'file_type' => $fieldKey, // field_key
|
'file_type' => $fileType, // 파일 형식 (image, document, excel, archive)
|
||||||
|
'field_key' => $fieldKey, // 비즈니스 용도 (drawing, certificate 등)
|
||||||
'document_id' => $id,
|
'document_id' => $id,
|
||||||
'document_type' => self::ITEM_GROUP_ID, // group_id
|
'document_type' => self::ITEM_GROUP_ID, // group_id
|
||||||
'is_temp' => false,
|
'is_temp' => false,
|
||||||
@@ -215,7 +220,8 @@ private function formatFileResponse(File $file): array
|
|||||||
'file_url' => $this->getFileUrl($file->file_path),
|
'file_url' => $this->getFileUrl($file->file_path),
|
||||||
'file_size' => $file->file_size,
|
'file_size' => $file->file_size,
|
||||||
'mime_type' => $file->mime_type,
|
'mime_type' => $file->mime_type,
|
||||||
'field_key' => $file->file_type,
|
'file_type' => $file->file_type,
|
||||||
|
'field_key' => $file->field_key,
|
||||||
'created_at' => $file->created_at?->format('Y-m-d H:i:s'),
|
'created_at' => $file->created_at?->format('Y-m-d H:i:s'),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -227,4 +233,34 @@ private function getFileUrl(string $filePath): string
|
|||||||
{
|
{
|
||||||
return url('/api/v1/files/download/'.base64_encode($filePath));
|
return url('/api/v1/files/download/'.base64_encode($filePath));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MIME 타입 기반 파일 형식 분류
|
||||||
|
*/
|
||||||
|
private function detectFileType(string $mimeType): string
|
||||||
|
{
|
||||||
|
if (str_starts_with($mimeType, 'image/')) {
|
||||||
|
return 'image';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_array($mimeType, [
|
||||||
|
'application/vnd.ms-excel',
|
||||||
|
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||||
|
'text/csv',
|
||||||
|
])) {
|
||||||
|
return 'excel';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_array($mimeType, [
|
||||||
|
'application/zip',
|
||||||
|
'application/x-rar-compressed',
|
||||||
|
'application/x-7z-compressed',
|
||||||
|
'application/gzip',
|
||||||
|
])) {
|
||||||
|
return 'archive';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 기본값: document (pdf, doc, hwp 등)
|
||||||
|
return 'document';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ class File extends Model
|
|||||||
'folder_id',
|
'folder_id',
|
||||||
'is_temp',
|
'is_temp',
|
||||||
'file_type',
|
'file_type',
|
||||||
|
'field_key',
|
||||||
'document_id',
|
'document_id',
|
||||||
'document_type',
|
'document_type',
|
||||||
'file_size',
|
'file_size',
|
||||||
|
|||||||
@@ -1147,7 +1147,7 @@ private function getItemFiles(int $itemId, int $tenantId): array
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
return $files->groupBy('file_type')->map(function ($group) {
|
return $files->groupBy('field_key')->map(function ($group) {
|
||||||
return $group->map(fn ($file) => [
|
return $group->map(fn ($file) => [
|
||||||
'id' => $file->id,
|
'id' => $file->id,
|
||||||
'file_name' => $file->display_name ?? $file->file_name,
|
'file_name' => $file->display_name ?? $file->file_name,
|
||||||
|
|||||||
@@ -17,26 +17,26 @@
|
|||||||
{
|
{
|
||||||
public function up(): void
|
public function up(): void
|
||||||
{
|
{
|
||||||
// 1. items 테이블 데이터 삭제
|
// FK 제약 조건 비활성화
|
||||||
if (Schema::hasTable('items')) {
|
DB::statement('SET FOREIGN_KEY_CHECKS=0');
|
||||||
$itemsCount = DB::table('items')->count();
|
|
||||||
echo "items 테이블 데이터 삭제: {$itemsCount}건\n";
|
|
||||||
DB::table('items')->truncate();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. item_id_mappings 테이블 삭제
|
// 1. item_id_mappings 테이블 먼저 삭제 (FK 참조)
|
||||||
if (Schema::hasTable('item_id_mappings')) {
|
if (Schema::hasTable('item_id_mappings')) {
|
||||||
$mappingsCount = DB::table('item_id_mappings')->count();
|
$mappingsCount = DB::table('item_id_mappings')->count();
|
||||||
echo "item_id_mappings 테이블 삭제: {$mappingsCount}건\n";
|
echo "item_id_mappings 테이블 삭제: {$mappingsCount}건\n";
|
||||||
Schema::dropIfExists('item_id_mappings');
|
Schema::dropIfExists('item_id_mappings');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. items 테이블 삭제
|
// 2. items 테이블 삭제
|
||||||
if (Schema::hasTable('items')) {
|
if (Schema::hasTable('items')) {
|
||||||
echo "items 테이블 삭제\n";
|
$itemsCount = DB::table('items')->count();
|
||||||
|
echo "items 테이블 삭제: {$itemsCount}건\n";
|
||||||
Schema::dropIfExists('items');
|
Schema::dropIfExists('items');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FK 제약 조건 재활성화
|
||||||
|
DB::statement('SET FOREIGN_KEY_CHECKS=1');
|
||||||
|
|
||||||
echo "✅ Items 관련 테이블 롤백 완료\n";
|
echo "✅ Items 관련 테이블 롤백 완료\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* files 테이블 수정
|
||||||
|
*
|
||||||
|
* 1. file_type: ENUM → VARCHAR(50) 변경 (확장성)
|
||||||
|
* 2. field_key: VARCHAR(100) 추가 (비즈니스 용도 구분)
|
||||||
|
*/
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
// 1. file_type ENUM → VARCHAR(50) 변경
|
||||||
|
DB::statement("ALTER TABLE `files` MODIFY `file_type` VARCHAR(50) NULL DEFAULT NULL COMMENT '파일 형식 (image, document, excel, archive 등)'");
|
||||||
|
|
||||||
|
// 2. field_key 컬럼 추가
|
||||||
|
if (! Schema::hasColumn('files', 'field_key')) {
|
||||||
|
Schema::table('files', function (Blueprint $table) {
|
||||||
|
$table->string('field_key', 100)
|
||||||
|
->nullable()
|
||||||
|
->after('file_type')
|
||||||
|
->comment('비즈니스 용도 구분 (drawing, certificate, specification 등)');
|
||||||
|
|
||||||
|
// 인덱스 추가 (document_type + document_id + field_key 조합 조회용)
|
||||||
|
$table->index(['document_type', 'document_id', 'field_key'], 'idx_files_document_field_key');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
// 1. field_key 컬럼 삭제
|
||||||
|
if (Schema::hasColumn('files', 'field_key')) {
|
||||||
|
Schema::table('files', function (Blueprint $table) {
|
||||||
|
$table->dropIndex('idx_files_document_field_key');
|
||||||
|
$table->dropColumn('field_key');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. file_type VARCHAR → ENUM 복원
|
||||||
|
DB::statement("ALTER TABLE `files` MODIFY `file_type` ENUM('document','image','excel','archive') NOT NULL");
|
||||||
|
}
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user