ApiResponse 헬퍼 확장 및 Tenant 요청 검증 개선

This commit is contained in:
2025-12-24 19:48:15 +09:00
parent cac8dba138
commit 0508282e58
4 changed files with 97 additions and 4 deletions

View File

@@ -1,6 +1,6 @@
# 논리적 데이터베이스 관계 문서
> **자동 생성**: 2025-12-23 22:25:44
> **자동 생성**: 2025-12-24 19:31:13
> **소스**: Eloquent 모델 관계 분석
## 📊 모델별 관계 현황
@@ -244,8 +244,10 @@ ### users
- **userTenants()**: hasMany → `user_tenants`
- **userRoles()**: hasMany → `user_roles`
- **tenantProfiles()**: hasMany → `tenant_user_profiles`
- **userTenant()**: hasOne → `user_tenants`
- **userTenantById()**: hasOne → `user_tenants`
- **tenantProfile()**: hasOne → `tenant_user_profiles`
- **tenantsMembership()**: belongsToMany → `tenants`
- **files()**: morphMany → `files`

View File

@@ -9,6 +9,80 @@
class ApiResponse
{
/**
* ISO 8601 날짜를 Y-m-d 형식으로 변환
*
* @param mixed $data 변환할 데이터 (배열, 객체, 페이지네이션 등)
* @return mixed 변환된 데이터
*/
public static function formatDates(mixed $data): mixed
{
// null이면 그대로 반환
if ($data === null) {
return null;
}
// Paginator 처리
if ($data instanceof \Illuminate\Pagination\LengthAwarePaginator ||
$data instanceof \Illuminate\Pagination\Paginator) {
$items = self::formatDates($data->items());
$data->setCollection(collect($items));
return $data;
}
// Collection 처리
if ($data instanceof \Illuminate\Support\Collection) {
return $data->map(fn ($item) => self::formatDates($item));
}
// Model 처리
if ($data instanceof \Illuminate\Database\Eloquent\Model) {
return self::formatDates($data->toArray());
}
// 배열 처리
if (is_array($data)) {
foreach ($data as $key => $value) {
if (is_string($value) && self::isIso8601Date($value)) {
$data[$key] = self::toDateFormat($value);
} elseif (is_array($value) || is_object($value)) {
$data[$key] = self::formatDates($value);
}
}
return $data;
}
// 단일 문자열이 ISO 8601 날짜인 경우
if (is_string($data) && self::isIso8601Date($data)) {
return self::toDateFormat($data);
}
return $data;
}
/**
* ISO 8601 날짜 형식인지 확인
*/
private static function isIso8601Date(string $value): bool
{
// 2025-12-22T15:00:00.000000Z 형식 매칭
return (bool) preg_match('/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?Z?$/', $value);
}
/**
* ISO 8601 날짜를 Y-m-d 형식으로 변환
*/
private static function toDateFormat(string $value): string
{
try {
return \Carbon\Carbon::parse($value)->format('Y-m-d');
} catch (\Exception $e) {
return $value;
}
}
public function normalizeFiles(array $laravelFiles): array
{
$files = ['name' => [], 'type' => [], 'tmp_name' => [], 'size' => [], 'fileType' => []];
@@ -51,10 +125,13 @@ public static function success(
array $debug = [],
int $statusCode = 200
): JsonResponse {
// ISO 8601 날짜를 Y-m-d 형식으로 변환
$formattedData = self::formatDates($data);
$response = [
'success' => true,
'message' => $message,
'data' => $data,
'data' => $formattedData,
];
if (! empty($debug)) {
$response['query'] = $debug;

View File

@@ -21,6 +21,18 @@ public function rules(): array
'address' => 'nullable|string|max:255',
'business_num' => 'nullable|string|max:20',
'ceo_name' => 'nullable|string|max:100',
// 확장 필드 (JSON)
'options' => 'nullable|array',
'options.business_type' => 'nullable|string|max:100',
'options.business_category' => 'nullable|string|max:100',
'options.zip_code' => 'nullable|string|max:10',
'options.address_detail' => 'nullable|string|max:255',
'options.tax_invoice_email' => 'nullable|email|max:100',
'options.manager_name' => 'nullable|string|max:100',
'options.payment_bank' => 'nullable|string|max:100',
'options.payment_account' => 'nullable|string|max:50',
'options.payment_account_holder' => 'nullable|string|max:100',
'options.payment_day' => 'nullable|string|max:10',
];
}
}

View File

@@ -8,10 +8,12 @@ trait ModelTrait
{
/**
* 날짜 직렬화 포맷 오버라이드 (모델에 추가해서 사용)
*
* ISO 8601 (2025-12-22T15:00:00.000000Z) → Y-m-d (2025-12-22)
*/
protected function serializeDate(DateTimeInterface $date)
protected function serializeDate(DateTimeInterface $date): string
{
return $date->format('Y-m-d H:i:s');
return $date->format('Y-m-d');
}
/**