230 lines
7.0 KiB
PHP
230 lines
7.0 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\Tenants\TenantOptionGroup;
|
|
use App\Models\Tenants\TenantOptionValue;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Validator;
|
|
use Illuminate\Validation\Rule;
|
|
|
|
class TenantOptionValueService
|
|
{
|
|
/** 활성 테넌트 ID */
|
|
protected static function tenantId(): ?int
|
|
{
|
|
return app('tenant_id');
|
|
}
|
|
|
|
/** 테넌트 소유 그룹 로드 (없으면 null) */
|
|
protected static function loadGroup(int $tenantId, int $groupId): ?TenantOptionGroup
|
|
{
|
|
return TenantOptionGroup::where('tenant_id', $tenantId)->find($groupId);
|
|
}
|
|
|
|
/**
|
|
* [GET] 옵션 값 목록
|
|
* params: active_only?(bool)
|
|
*/
|
|
public static function index(int $groupId, array $params = [])
|
|
{
|
|
$tenantId = self::tenantId();
|
|
if (! $tenantId) {
|
|
return ['error' => '활성 테넌트가 없습니다.', 'code' => 400];
|
|
}
|
|
|
|
$group = self::loadGroup($tenantId, $groupId);
|
|
if (! $group) {
|
|
return ['error' => '옵션 그룹을 찾을 수 없습니다.', 'code' => 404];
|
|
}
|
|
|
|
$q = TenantOptionValue::where('group_id', $group->id)
|
|
->orderBy('sort_order')
|
|
->orderBy('value_label');
|
|
|
|
if (! empty($params['active_only'])) {
|
|
$q->where('is_active', 1);
|
|
}
|
|
|
|
$list = $q->get();
|
|
|
|
return $list;
|
|
}
|
|
|
|
/**
|
|
* [POST] 옵션 값 생성
|
|
*/
|
|
public static function store(int $groupId, array $params = [])
|
|
{
|
|
$tenantId = self::tenantId();
|
|
if (! $tenantId) {
|
|
return ['error' => '활성 테넌트가 없습니다.', 'code' => 400];
|
|
}
|
|
|
|
$group = self::loadGroup($tenantId, $groupId);
|
|
if (! $group) {
|
|
return ['error' => '옵션 그룹을 찾을 수 없습니다.', 'code' => 404];
|
|
}
|
|
|
|
$v = Validator::make($params, [
|
|
'value_key' => [
|
|
'required', 'string', 'max:64', 'alpha_dash',
|
|
Rule::unique('tenant_option_values', 'value_key')
|
|
->where(fn ($q) => $q->where('group_id', $group->id)),
|
|
],
|
|
'value_label' => ['required', 'string', 'max:100'],
|
|
'sort_order' => ['nullable', 'integer'],
|
|
'is_active' => ['nullable', 'boolean'],
|
|
]);
|
|
|
|
if ($v->fails()) {
|
|
return ['error' => $v->errors()->first(), 'code' => 422];
|
|
}
|
|
|
|
$data = $v->validated();
|
|
$data['group_id'] = $group->id;
|
|
$item = TenantOptionValue::create($data);
|
|
|
|
return $item->toArray();
|
|
}
|
|
|
|
/**
|
|
* [GET] 옵션 값 단건 조회
|
|
*/
|
|
public static function show(int $groupId, int $id)
|
|
{
|
|
$tenantId = self::tenantId();
|
|
if (! $tenantId) {
|
|
return ['error' => '활성 테넌트가 없습니다.', 'code' => 400];
|
|
}
|
|
|
|
$group = self::loadGroup($tenantId, $groupId);
|
|
if (! $group) {
|
|
return ['error' => '옵션 그룹을 찾을 수 없습니다.', 'code' => 404];
|
|
}
|
|
|
|
$item = TenantOptionValue::where('group_id', $group->id)->find($id);
|
|
if (! $item) {
|
|
return ['error' => '옵션 값을 찾을 수 없습니다.', 'code' => 404];
|
|
}
|
|
|
|
return $item->toArray();
|
|
}
|
|
|
|
/**
|
|
* [PATCH] 옵션 값 수정
|
|
*/
|
|
public static function update(int $groupId, int $id, array $params = [])
|
|
{
|
|
$tenantId = self::tenantId();
|
|
if (! $tenantId) {
|
|
return ['error' => '활성 테넌트가 없습니다.', 'code' => 400];
|
|
}
|
|
|
|
$group = self::loadGroup($tenantId, $groupId);
|
|
if (! $group) {
|
|
return ['error' => '옵션 그룹을 찾을 수 없습니다.', 'code' => 404];
|
|
}
|
|
|
|
$item = TenantOptionValue::where('group_id', $group->id)->find($id);
|
|
if (! $item) {
|
|
return ['error' => '옵션 값을 찾을 수 없습니다.', 'code' => 404];
|
|
}
|
|
|
|
$v = Validator::make($params, [
|
|
'value_key' => [
|
|
'sometimes', 'string', 'max:64', 'alpha_dash',
|
|
Rule::unique('tenant_option_values', 'value_key')
|
|
->where(fn ($q) => $q->where('group_id', $group->id))
|
|
->ignore($item->id),
|
|
],
|
|
'value_label' => ['sometimes', 'string', 'max:100'],
|
|
'sort_order' => ['nullable', 'integer'],
|
|
'is_active' => ['nullable', 'boolean'],
|
|
]);
|
|
|
|
if ($v->fails()) {
|
|
return ['error' => $v->errors()->first(), 'code' => 422];
|
|
}
|
|
|
|
$data = $v->validated();
|
|
if (empty($data)) {
|
|
return ['error' => '수정할 항목이 없습니다.', 'code' => 422];
|
|
}
|
|
|
|
$item->fill($data)->save();
|
|
|
|
return $item->toArray();
|
|
}
|
|
|
|
/**
|
|
* [DELETE] 옵션 값 삭제
|
|
* - TODO: 실제 프로필/필드설정에서 value_key 참조 여부 체크가 필요하면 여기서 차단
|
|
*/
|
|
public static function destroy(int $groupId, int $id)
|
|
{
|
|
$tenantId = self::tenantId();
|
|
if (! $tenantId) {
|
|
return ['error' => '활성 테넌트가 없습니다.', 'code' => 400];
|
|
}
|
|
|
|
$group = self::loadGroup($tenantId, $groupId);
|
|
if (! $group) {
|
|
return ['error' => '옵션 그룹을 찾을 수 없습니다.', 'code' => 404];
|
|
}
|
|
|
|
$item = TenantOptionValue::where('group_id', $group->id)->find($id);
|
|
if (! $item) {
|
|
return ['error' => '옵션 값을 찾을 수 없습니다.', 'code' => 404];
|
|
}
|
|
|
|
// TODO: 참조 무결성 검사(필요 시 구현)
|
|
$item->delete();
|
|
|
|
return ['deleted' => true];
|
|
}
|
|
|
|
/**
|
|
* [PATCH] 정렬 순서 일괄 변경
|
|
* params: items: [{id, sort_order}, ...]
|
|
*/
|
|
public static function reorder(int $groupId, array $params = [])
|
|
{
|
|
$tenantId = self::tenantId();
|
|
if (! $tenantId) {
|
|
return ['error' => '활성 테넌트가 없습니다.', 'code' => 400];
|
|
}
|
|
|
|
$group = self::loadGroup($tenantId, $groupId);
|
|
if (! $group) {
|
|
return ['error' => '옵션 그룹을 찾을 수 없습니다.', 'code' => 404];
|
|
}
|
|
|
|
$v = Validator::make($params, [
|
|
'items' => ['required', 'array', 'min:1'],
|
|
'items.*.id' => ['required', 'integer'],
|
|
'items.*.sort_order' => ['required', 'integer'],
|
|
]);
|
|
|
|
if ($v->fails()) {
|
|
return ['error' => $v->errors()->first(), 'code' => 422];
|
|
}
|
|
|
|
$rows = $v->validated()['items'];
|
|
|
|
try {
|
|
DB::transaction(function () use ($group, $rows) {
|
|
foreach ($rows as $r) {
|
|
TenantOptionValue::where('group_id', $group->id)
|
|
->where('id', $r['id'])
|
|
->update(['sort_order' => (int) $r['sort_order']]);
|
|
}
|
|
});
|
|
} catch (\Throwable $e) {
|
|
return ['error' => '정렬 순서 저장 중 오류가 발생했습니다.', 'code' => 500];
|
|
}
|
|
|
|
return ['reordered' => true];
|
|
}
|
|
}
|