tenantId(); $size = (int) ($params['size'] ?? 20); $sort = $params['sort'] ?? 'sort_order'; $order = strtolower($params['order'] ?? 'asc') === 'desc' ? 'desc' : 'asc'; return CategoryField::query() ->where('tenant_id', $tenantId) ->where('category_id', $categoryId) ->orderBy($sort, $order) ->paginate($size); } public function store(int $categoryId, array $data) { $tenantId = $this->tenantId(); $userId = $this->apiUserId(); $this->assertCategoryExists($tenantId, $categoryId); // FormRequest에서 이미 검증됨 $payload = $data; // 카테고리 내 field_key 유니크 검증 $exists = CategoryField::query() ->where('tenant_id', $tenantId) ->where('category_id', $categoryId) ->where('field_key', $payload['field_key']) ->exists(); if ($exists) { throw new BadRequestHttpException(__('error.duplicate_key')); } $payload['tenant_id'] = $tenantId; $payload['category_id'] = $categoryId; $payload['is_required'] = $payload['is_required'] ?? false; $payload['sort_order'] = $payload['sort_order'] ?? 0; $payload['created_by'] = $userId; return CategoryField::create($payload); } public function show(int $fieldId) { $tenantId = $this->tenantId(); $field = CategoryField::query() ->where('tenant_id', $tenantId) ->find($fieldId); if (! $field) { throw new BadRequestHttpException(__('error.not_found')); } return $field; } public function update(int $fieldId, array $data) { $tenantId = $this->tenantId(); $userId = $this->apiUserId(); $field = CategoryField::query() ->where('tenant_id', $tenantId) ->find($fieldId); if (! $field) { throw new BadRequestHttpException(__('error.not_found')); } // FormRequest에서 이미 검증됨 $payload = $data; if (isset($payload['field_key']) && $payload['field_key'] !== $field->field_key) { $dup = CategoryField::query() ->where('tenant_id', $tenantId) ->where('category_id', $field->category_id) ->where('field_key', $payload['field_key']) ->exists(); if ($dup) { throw new BadRequestHttpException(__('error.duplicate_key')); } } $payload['updated_by'] = $userId; $field->update($payload); return $field->refresh(); } public function destroy(int $fieldId): void { $tenantId = $this->tenantId(); $field = CategoryField::query() ->where('tenant_id', $tenantId) ->find($fieldId); if (! $field) { throw new BadRequestHttpException(__('error.not_found')); } $field->delete(); } public function reorder(int $categoryId, array $items): void { $tenantId = $this->tenantId(); $this->assertCategoryExists($tenantId, $categoryId); $rows = $items['items'] ?? $items; // 둘 다 허용 if (! is_array($rows)) { throw new BadRequestHttpException(__('error.invalid_payload')); } DB::transaction(function () use ($tenantId, $categoryId, $rows) { foreach ($rows as $row) { if (! isset($row['id'], $row['sort_order'])) { continue; } CategoryField::query() ->where('tenant_id', $tenantId) ->where('category_id', $categoryId) ->where('id', $row['id']) ->update(['sort_order' => (int) $row['sort_order']]); } }); } public function bulkUpsert(int $categoryId, array $items): array { $tenantId = $this->tenantId(); $userId = $this->apiUserId(); $this->assertCategoryExists($tenantId, $categoryId); if (! is_array($items) || empty($items)) { throw new BadRequestHttpException(__('error.empty_items')); } $result = ['created' => 0, 'updated' => 0]; DB::transaction(function () use ($tenantId, $userId, $categoryId, $items, &$result) { foreach ($items as $payload) { // 기본적인 검증 (FormRequest가 배열 내부까지는 검증 못함) if (! isset($payload['field_name'], $payload['field_type'])) { throw new BadRequestHttpException(__('error.invalid_payload')); } if (! empty($payload['id'])) { $model = CategoryField::query() ->where('tenant_id', $tenantId) ->where('category_id', $categoryId) ->find($payload['id']); if (! $model) { throw new BadRequestHttpException(__('error.not_found')); } // field_key 변경 유니크 검사 if (isset($payload['field_key']) && $payload['field_key'] !== $model->field_key) { $dup = CategoryField::query() ->where('tenant_id', $tenantId) ->where('category_id', $categoryId) ->where('field_key', $payload['field_key']) ->exists(); if ($dup) { throw new BadRequestHttpException(__('error.duplicate_key')); } } $payload['updated_by'] = $userId; $model->update($payload); $result['updated']++; } else { // 신규 생성 if (empty($payload['field_key'])) { throw new BadRequestHttpException(__('error.required', ['attr' => 'field_key'])); } $dup = CategoryField::query() ->where('tenant_id', $tenantId) ->where('category_id', $categoryId) ->where('field_key', $payload['field_key']) ->exists(); if ($dup) { throw new BadRequestHttpException(__('error.duplicate_key')); } $payload['tenant_id'] = $tenantId; $payload['category_id'] = $categoryId; $payload['is_required'] = $payload['is_required'] ?? false; $payload['sort_order'] = $payload['sort_order'] ?? 0; $payload['created_by'] = $userId; CategoryField::create($payload); $result['created']++; } } }); return $result; } private function assertCategoryExists(int $tenantId, int $categoryId): void { $exists = Category::query() ->where('tenant_id', $tenantId) ->where('id', $categoryId) ->exists(); if (! $exists) { throw new BadRequestHttpException(__('error.category_not_found')); } } }