2025-08-18 19:03:46 +09:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
namespace App\Services;
|
|
|
|
|
|
2025-11-06 17:45:49 +09:00
|
|
|
use App\Models\Tenants\TenantFieldSetting;
|
2025-08-18 19:03:46 +09:00
|
|
|
use App\Models\Tenants\TenantOptionGroup;
|
|
|
|
|
use App\Models\Tenants\TenantOptionValue;
|
2025-11-06 17:45:49 +09:00
|
|
|
use Illuminate\Support\Facades\Validator;
|
|
|
|
|
use Illuminate\Validation\Rule;
|
2025-08-18 19:03:46 +09:00
|
|
|
|
|
|
|
|
class TenantOptionGroupService
|
|
|
|
|
{
|
|
|
|
|
/** 활성 테넌트 ID */
|
|
|
|
|
protected static function tenantId(): ?int
|
|
|
|
|
{
|
|
|
|
|
return app('tenant_id');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* [GET] 옵션 그룹 목록 (페이징)
|
|
|
|
|
* params: page?, per_page?/size?, q?
|
|
|
|
|
*/
|
|
|
|
|
public static function index(array $params = [])
|
|
|
|
|
{
|
|
|
|
|
$tenantId = self::tenantId();
|
2025-11-06 17:45:49 +09:00
|
|
|
if (! $tenantId) {
|
2025-08-19 12:41:17 +09:00
|
|
|
return ['error' => '활성 테넌트가 없습니다.', 'code' => 400];
|
2025-08-18 19:03:46 +09:00
|
|
|
}
|
|
|
|
|
|
2025-11-06 17:45:49 +09:00
|
|
|
$per = (int) ($params['per_page'] ?? $params['size'] ?? 20);
|
|
|
|
|
$page = isset($params['page']) ? (int) $params['page'] : null;
|
2025-08-18 19:03:46 +09:00
|
|
|
|
|
|
|
|
$q = TenantOptionGroup::where('tenant_id', $tenantId)->orderBy('group_key');
|
|
|
|
|
|
2025-11-06 17:45:49 +09:00
|
|
|
if (! empty($params['q'])) {
|
2025-08-18 19:03:46 +09:00
|
|
|
$kw = $params['q'];
|
|
|
|
|
$q->where(function ($w) use ($kw) {
|
|
|
|
|
$w->where('group_key', 'like', "%{$kw}%")
|
|
|
|
|
->orWhere('name', 'like', "%{$kw}%");
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$data = $q->paginate($per, ['*'], 'page', $page);
|
|
|
|
|
|
2025-08-19 12:41:17 +09:00
|
|
|
return $data;
|
2025-08-18 19:03:46 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* [POST] 옵션 그룹 생성
|
|
|
|
|
*/
|
|
|
|
|
public static function store(array $params = [])
|
|
|
|
|
{
|
|
|
|
|
$tenantId = self::tenantId();
|
2025-11-06 17:45:49 +09:00
|
|
|
if (! $tenantId) {
|
2025-08-19 12:41:17 +09:00
|
|
|
return ['error' => '활성 테넌트가 없습니다.', 'code' => 400];
|
2025-08-18 19:03:46 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$v = Validator::make($params, [
|
|
|
|
|
'group_key' => [
|
2025-11-06 17:45:49 +09:00
|
|
|
'required', 'string', 'max:64', 'alpha_dash',
|
2025-08-18 19:03:46 +09:00
|
|
|
Rule::unique('tenant_option_groups', 'group_key')
|
|
|
|
|
->where(fn ($q) => $q->where('tenant_id', $tenantId)),
|
|
|
|
|
],
|
2025-11-06 17:45:49 +09:00
|
|
|
'name' => ['required', 'string', 'max:100'],
|
|
|
|
|
'description' => ['nullable', 'string', 'max:255'],
|
2025-08-18 19:03:46 +09:00
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
if ($v->fails()) {
|
2025-08-19 12:41:17 +09:00
|
|
|
return ['error' => $v->errors()->first(), 'code' => 422];
|
2025-08-18 19:03:46 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$data = $v->validated();
|
|
|
|
|
$data['tenant_id'] = $tenantId;
|
|
|
|
|
|
|
|
|
|
$item = TenantOptionGroup::create($data);
|
|
|
|
|
|
2025-08-19 12:41:17 +09:00
|
|
|
return $item->toArray();
|
2025-08-18 19:03:46 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* [GET] 옵션 그룹 단건 조회
|
|
|
|
|
*/
|
|
|
|
|
public static function show(int $id)
|
|
|
|
|
{
|
|
|
|
|
$tenantId = self::tenantId();
|
2025-11-06 17:45:49 +09:00
|
|
|
if (! $tenantId) {
|
2025-08-19 12:41:17 +09:00
|
|
|
return ['error' => '활성 테넌트가 없습니다.', 'code' => 400];
|
2025-08-18 19:03:46 +09:00
|
|
|
}
|
2025-11-06 17:45:49 +09:00
|
|
|
if (! $id) {
|
2025-08-19 12:41:17 +09:00
|
|
|
return ['error' => 'id가 올바르지 않습니다.', 'code' => 422];
|
2025-08-18 19:03:46 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$item = TenantOptionGroup::where('tenant_id', $tenantId)->find($id);
|
2025-11-06 17:45:49 +09:00
|
|
|
if (! $item) {
|
2025-08-19 12:41:17 +09:00
|
|
|
return ['error' => '옵션 그룹을 찾을 수 없습니다.', 'code' => 404];
|
2025-08-18 19:03:46 +09:00
|
|
|
}
|
|
|
|
|
|
2025-08-19 12:41:17 +09:00
|
|
|
return $item->toArray();
|
2025-08-18 19:03:46 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* [PATCH] 옵션 그룹 수정
|
|
|
|
|
*/
|
|
|
|
|
public static function update(int $id, array $params = [])
|
|
|
|
|
{
|
|
|
|
|
$tenantId = self::tenantId();
|
2025-11-06 17:45:49 +09:00
|
|
|
if (! $tenantId) {
|
2025-08-19 12:41:17 +09:00
|
|
|
return ['error' => '활성 테넌트가 없습니다.', 'code' => 400];
|
2025-08-18 19:03:46 +09:00
|
|
|
}
|
2025-11-06 17:45:49 +09:00
|
|
|
if (! $id) {
|
2025-08-19 12:41:17 +09:00
|
|
|
return ['error' => 'id가 올바르지 않습니다.', 'code' => 422];
|
2025-08-18 19:03:46 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$item = TenantOptionGroup::where('tenant_id', $tenantId)->find($id);
|
2025-11-06 17:45:49 +09:00
|
|
|
if (! $item) {
|
2025-08-19 12:41:17 +09:00
|
|
|
return ['error' => '옵션 그룹을 찾을 수 없습니다.', 'code' => 404];
|
2025-08-18 19:03:46 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$v = Validator::make($params, [
|
|
|
|
|
'group_key' => [
|
2025-11-06 17:45:49 +09:00
|
|
|
'sometimes', 'string', 'max:64', 'alpha_dash',
|
2025-08-18 19:03:46 +09:00
|
|
|
Rule::unique('tenant_option_groups', 'group_key')
|
|
|
|
|
->where(fn ($q) => $q->where('tenant_id', $tenantId))
|
|
|
|
|
->ignore($item->id),
|
|
|
|
|
],
|
2025-11-06 17:45:49 +09:00
|
|
|
'name' => ['sometimes', 'string', 'max:100'],
|
|
|
|
|
'description' => ['nullable', 'string', 'max:255'],
|
2025-08-18 19:03:46 +09:00
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
if ($v->fails()) {
|
2025-08-19 12:41:17 +09:00
|
|
|
return ['error' => $v->errors()->first(), 'code' => 422];
|
2025-08-18 19:03:46 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$data = $v->validated();
|
|
|
|
|
if (empty($data)) {
|
2025-08-19 12:41:17 +09:00
|
|
|
return ['error' => '수정할 항목이 없습니다.', 'code' => 422];
|
2025-08-18 19:03:46 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$item->fill($data)->save();
|
|
|
|
|
|
2025-08-19 12:41:17 +09:00
|
|
|
return $item->toArray();
|
2025-08-18 19:03:46 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* [DELETE] 옵션 그룹 삭제
|
|
|
|
|
* - 참조 무결성 검사:
|
|
|
|
|
* 1) tenant_option_values에 값이 남아있으면 삭제 불가
|
|
|
|
|
* 2) tenant_field_settings.option_group_id에서 참조 중이면 삭제 불가
|
|
|
|
|
*/
|
|
|
|
|
public static function destroy(int $id)
|
|
|
|
|
{
|
|
|
|
|
$tenantId = self::tenantId();
|
2025-11-06 17:45:49 +09:00
|
|
|
if (! $tenantId) {
|
2025-08-19 12:41:17 +09:00
|
|
|
return ['error' => '활성 테넌트가 없습니다.', 'code' => 400];
|
2025-08-18 19:03:46 +09:00
|
|
|
}
|
2025-11-06 17:45:49 +09:00
|
|
|
if (! $id) {
|
2025-08-19 12:41:17 +09:00
|
|
|
return ['error' => 'id가 올바르지 않습니다.', 'code' => 422];
|
2025-08-18 19:03:46 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$item = TenantOptionGroup::where('tenant_id', $tenantId)->find($id);
|
2025-11-06 17:45:49 +09:00
|
|
|
if (! $item) {
|
2025-08-19 12:41:17 +09:00
|
|
|
return ['error' => '옵션 그룹을 찾을 수 없습니다.', 'code' => 404];
|
2025-08-18 19:03:46 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 1) 옵션 값 존재 여부
|
|
|
|
|
$hasValues = TenantOptionValue::where('group_id', $item->id)->exists();
|
|
|
|
|
if ($hasValues) {
|
2025-08-19 12:41:17 +09:00
|
|
|
return ['error' => '해당 그룹에 옵션 값이 존재하여 삭제할 수 없습니다.', 'code' => 409];
|
2025-08-18 19:03:46 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 2) 필드 설정에서 참조 여부
|
|
|
|
|
$isReferenced = TenantFieldSetting::where('tenant_id', $tenantId)
|
|
|
|
|
->where('option_group_id', $item->id)
|
|
|
|
|
->exists();
|
|
|
|
|
if ($isReferenced) {
|
2025-08-19 12:41:17 +09:00
|
|
|
return ['error' => '필드 설정에서 참조 중인 그룹은 삭제할 수 없습니다.', 'code' => 409];
|
2025-08-18 19:03:46 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$item->delete();
|
|
|
|
|
|
2025-08-19 12:41:17 +09:00
|
|
|
return ['deleted' => true];
|
2025-08-18 19:03:46 +09:00
|
|
|
}
|
|
|
|
|
}
|