301 lines
7.0 KiB
Markdown
301 lines
7.0 KiB
Markdown
|
|
# Items API files 배열 에러 수정
|
||
|
|
|
||
|
|
## 날짜
|
||
|
|
2025-12-15
|
||
|
|
|
||
|
|
## 문제
|
||
|
|
`PUT /api/v1/items/{id}` 요청 시 500 에러 발생
|
||
|
|
```
|
||
|
|
"Array to string conversion"
|
||
|
|
```
|
||
|
|
|
||
|
|
## 원인 분석
|
||
|
|
1. API 요청에서 `files` 배열이 전송됨:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"files": {
|
||
|
|
"drawing": [{
|
||
|
|
"id": 5,
|
||
|
|
"file_name": "IMG_2163.png",
|
||
|
|
"file_path": "287/items/2025/12/ec3483f4152d1eb1.png"
|
||
|
|
}]
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
2. `ItemsService::getKnownFields()`의 `$apiFields`에 `files`가 없어서 동적 필드로 인식됨
|
||
|
|
|
||
|
|
3. `extractDynamicOptions()`에서 `files`가 "알려지지 않은 필드"로 추출됨
|
||
|
|
|
||
|
|
4. `$product->update($data)` 호출 시 `files` 배열이 그대로 전달되어 DB 저장 시 에러 발생
|
||
|
|
|
||
|
|
## 수정 파일
|
||
|
|
`api/app/Services/ItemsService.php`
|
||
|
|
|
||
|
|
## 수정 내용
|
||
|
|
|
||
|
|
### 1. getKnownFields() 메서드 (라인 36-37)
|
||
|
|
```php
|
||
|
|
// 수정 전
|
||
|
|
$apiFields = ['item_type', 'type_code', 'bom', 'product_type'];
|
||
|
|
|
||
|
|
// 수정 후
|
||
|
|
$apiFields = ['item_type', 'type_code', 'bom', 'product_type', 'files'];
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2. updateProduct() 메서드 (라인 729-730)
|
||
|
|
```php
|
||
|
|
// 수정 전
|
||
|
|
unset($data['item_type']);
|
||
|
|
|
||
|
|
// 수정 후
|
||
|
|
unset($data['item_type'], $data['files']);
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3. updateMaterial() 메서드 (라인 771-772)
|
||
|
|
```php
|
||
|
|
// 수정 전
|
||
|
|
unset($data['item_type'], $data['code']);
|
||
|
|
|
||
|
|
// 수정 후
|
||
|
|
unset($data['item_type'], $data['code'], $data['files']);
|
||
|
|
```
|
||
|
|
|
||
|
|
## 적용 체크리스트
|
||
|
|
- [x] `getKnownFields()` - `$apiFields`에 `'files'` 추가
|
||
|
|
- [x] `updateProduct()` - `unset()`에 `$data['files']` 추가
|
||
|
|
- [x] `updateMaterial()` - `unset()`에 `$data['files']` 추가
|
||
|
|
|
||
|
|
## 커밋 정보
|
||
|
|
```
|
||
|
|
c68c280 fix: Items API 수정 시 files 배열로 인한 500 에러 수정
|
||
|
|
```
|
||
|
|
|
||
|
|
## 관련 파일
|
||
|
|
- `api/app/Http/Controllers/Api/V1/ItemsController.php`
|
||
|
|
- `api/app/Http/Controllers/Api/V1/ItemsFileController.php`
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
# ItemsFileController delete 메서드 타입 에러 수정
|
||
|
|
|
||
|
|
## 날짜
|
||
|
|
2025-12-15
|
||
|
|
|
||
|
|
## 문제
|
||
|
|
`DELETE /api/v1/items/{id}/files/{fileId}` 요청 시 타입 에러 발생
|
||
|
|
```
|
||
|
|
Argument #2 ($fileId) must be of type int, string given
|
||
|
|
```
|
||
|
|
|
||
|
|
## 원인 분석
|
||
|
|
Laravel 라우트 파라미터는 기본적으로 string으로 전달되는데, 컨트롤러 메서드에서 `int` 타입힌트를 사용하여 에러 발생
|
||
|
|
|
||
|
|
## 수정 파일
|
||
|
|
`api/app/Http/Controllers/Api/V1/ItemsFileController.php`
|
||
|
|
|
||
|
|
## 수정 내용
|
||
|
|
|
||
|
|
### delete() 메서드 (라인 157-159)
|
||
|
|
```php
|
||
|
|
// 수정 전
|
||
|
|
public function delete(int $id, int $fileId, Request $request)
|
||
|
|
{
|
||
|
|
return ApiResponse::handle(function () use ($id, $fileId, $request) {
|
||
|
|
|
||
|
|
// 수정 후
|
||
|
|
public function delete(int $id, mixed $fileId, Request $request)
|
||
|
|
{
|
||
|
|
$fileId = (int) $fileId;
|
||
|
|
|
||
|
|
return ApiResponse::handle(function () use ($id, $fileId, $request) {
|
||
|
|
```
|
||
|
|
|
||
|
|
## 적용 체크리스트
|
||
|
|
- [x] `delete()` 메서드 - `$fileId` 파라미터 타입을 `mixed`로 변경
|
||
|
|
- [x] `delete()` 메서드 - 내부에서 `$fileId = (int) $fileId;` 캐스팅 추가
|
||
|
|
|
||
|
|
## 커밋 정보
|
||
|
|
```
|
||
|
|
1040ce0 fix: ItemsFileController delete 메서드 타입 에러 수정
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
# ItemsFileController userId null 처리
|
||
|
|
|
||
|
|
## 날짜
|
||
|
|
2025-12-15
|
||
|
|
|
||
|
|
## 문제
|
||
|
|
`DELETE /api/v1/items/{id}/files/{fileId}` 요청 시 500 에러 발생
|
||
|
|
```
|
||
|
|
softDeleteFile(): Argument #1 ($userId) must be of type int, null given
|
||
|
|
```
|
||
|
|
|
||
|
|
## 원인 분석
|
||
|
|
- `auth()->id()`가 `null`을 반환
|
||
|
|
- API 키 인증만 사용하고 Sanctum 토큰 인증이 없는 경우 발생
|
||
|
|
- `softDeleteFile(int $userId)` 메서드에 null 전달 시 타입 에러
|
||
|
|
|
||
|
|
## 수정 파일
|
||
|
|
`api/app/Http/Controllers/Api/V1/ItemsFileController.php`
|
||
|
|
|
||
|
|
## 수정 내용
|
||
|
|
|
||
|
|
### 1. upload() 메서드 (라인 77)
|
||
|
|
```php
|
||
|
|
// 수정 전
|
||
|
|
$userId = auth()->id();
|
||
|
|
|
||
|
|
// 수정 후
|
||
|
|
$userId = auth()->id() ?? app('api_user');
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2. delete() 메서드 (라인 163)
|
||
|
|
```php
|
||
|
|
// 수정 전
|
||
|
|
$userId = auth()->id();
|
||
|
|
|
||
|
|
// 수정 후
|
||
|
|
$userId = auth()->id() ?? app('api_user');
|
||
|
|
```
|
||
|
|
|
||
|
|
## 적용 체크리스트
|
||
|
|
- [x] `upload()` 메서드 - `auth()->id() ?? app('api_user')` 변경
|
||
|
|
- [x] `delete()` 메서드 - `auth()->id() ?? app('api_user')` 변경
|
||
|
|
|
||
|
|
## 커밋 정보
|
||
|
|
```
|
||
|
|
22abb99 fix: ItemsFileController userId null 처리 추가
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
# ItemsFileController 파일 삭제 로직 일원화
|
||
|
|
|
||
|
|
## 날짜
|
||
|
|
2025-12-15
|
||
|
|
|
||
|
|
## 문제
|
||
|
|
- `upload()` 메서드의 파일 교체 삭제와 `delete()` 메서드의 파일 삭제 로직이 분리되어 있음
|
||
|
|
- userId 캐스팅이 일관되지 않음 (upload에만 int 캐스팅 적용)
|
||
|
|
- 관리 포인트가 2곳으로 분산
|
||
|
|
|
||
|
|
## 수정 파일
|
||
|
|
`api/app/Http/Controllers/Api/V1/ItemsFileController.php`
|
||
|
|
|
||
|
|
## 수정 내용
|
||
|
|
|
||
|
|
### 1. deleteFile() private 메서드 추가 (라인 195-199)
|
||
|
|
```php
|
||
|
|
// 추가
|
||
|
|
private function deleteFile(File $file): void
|
||
|
|
{
|
||
|
|
$userId = (int) (auth()->id() ?? app('api_user'));
|
||
|
|
$file->softDeleteFile($userId);
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2. upload() 메서드 - 기존 파일 교체 시 (라인 98-100)
|
||
|
|
```php
|
||
|
|
// 수정 전
|
||
|
|
if ($existingFile) {
|
||
|
|
$existingFile->softDeleteFile($userId);
|
||
|
|
$replaced = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 수정 후
|
||
|
|
if ($existingFile) {
|
||
|
|
$this->deleteFile($existingFile);
|
||
|
|
$replaced = true;
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3. delete() 메서드 (라인 180-181)
|
||
|
|
```php
|
||
|
|
// 수정 전
|
||
|
|
$userId = auth()->id() ?? app('api_user');
|
||
|
|
...
|
||
|
|
$file->softDeleteFile($userId);
|
||
|
|
|
||
|
|
// 수정 후
|
||
|
|
// $userId 변수 제거
|
||
|
|
$this->deleteFile($file);
|
||
|
|
```
|
||
|
|
|
||
|
|
## 적용 체크리스트
|
||
|
|
- [x] `deleteFile()` private 메서드 추가
|
||
|
|
- [x] `upload()` 메서드 - `$this->deleteFile($existingFile)` 사용
|
||
|
|
- [x] `delete()` 메서드 - `$userId` 변수 제거, `$this->deleteFile($file)` 사용
|
||
|
|
|
||
|
|
## 커밋 정보
|
||
|
|
```
|
||
|
|
dea414b refactor: ItemsFileController 파일 삭제 로직 일원화
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
# ItemsFileController 파일 다운로드 URL 수정
|
||
|
|
|
||
|
|
## 날짜
|
||
|
|
2025-12-15
|
||
|
|
|
||
|
|
## 문제
|
||
|
|
파일 다운로드 시 인증 오류 발생
|
||
|
|
- 생성되는 URL: `/api/v1/files/download/{base64_path}` (라우트 없음)
|
||
|
|
- 실제 라우트: `/api/v1/files/{id}/download`
|
||
|
|
|
||
|
|
## 수정 파일
|
||
|
|
`api/app/Http/Controllers/Api/V1/ItemsFileController.php`
|
||
|
|
|
||
|
|
## 수정 내용
|
||
|
|
|
||
|
|
### 1. getFileUrl() 메서드 (라인 244-247)
|
||
|
|
```php
|
||
|
|
// 수정 전
|
||
|
|
private function getFileUrl(string $filePath): string
|
||
|
|
{
|
||
|
|
return url('/api/v1/files/download/'.base64_encode($filePath));
|
||
|
|
}
|
||
|
|
|
||
|
|
// 수정 후
|
||
|
|
private function getFileUrl(int $fileId): string
|
||
|
|
{
|
||
|
|
return url("/api/v1/files/{$fileId}/download");
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2. formatFileResponse() 메서드 (라인 232)
|
||
|
|
```php
|
||
|
|
// 수정 전
|
||
|
|
'file_url' => $this->getFileUrl($file->file_path),
|
||
|
|
|
||
|
|
// 수정 후
|
||
|
|
'file_url' => $this->getFileUrl($file->id),
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3. upload() 응답 (라인 142)
|
||
|
|
```php
|
||
|
|
// 수정 전
|
||
|
|
'file_url' => $this->getFileUrl($filePath),
|
||
|
|
|
||
|
|
// 수정 후
|
||
|
|
'file_url' => $this->getFileUrl($file->id),
|
||
|
|
```
|
||
|
|
|
||
|
|
## 적용 체크리스트
|
||
|
|
- [x] `getFileUrl()` 메서드 - 파라미터를 `string $filePath` → `int $fileId`로 변경
|
||
|
|
- [x] `getFileUrl()` 메서드 - URL 형식을 `/api/v1/files/{id}/download`로 변경
|
||
|
|
- [x] `formatFileResponse()` - `$this->getFileUrl($file->id)` 사용
|
||
|
|
- [x] `upload()` 응답 - `$this->getFileUrl($file->id)` 사용
|
||
|
|
|
||
|
|
## 프론트엔드 참고
|
||
|
|
- 다운로드 요청 시 **API 키 헤더 필수** (`X-API-Key` 또는 설정된 헤더)
|
||
|
|
- 기존 FileStorageController의 download 라우트 활용
|
||
|
|
|
||
|
|
## 커밋 정보
|
||
|
|
```
|
||
|
|
98262ed fix: ItemsFileController 파일 다운로드 URL을 file_id 기반으로 변경
|
||
|
|
```
|