Files
sam-api/app/Services/MenuService.php
kent 73d06e03b0 fix : 권한관리 기능 추가 (각 기능 확인 필요)
- 메뉴관리
- 역할관리
- 부서관리
- 메뉴, 부서, 역할, 유저 - 권한 연동
2025-08-16 03:25:50 +09:00

221 lines
8.3 KiB
PHP

<?php
namespace App\Services;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Arr;
use Illuminate\Validation\ValidationException;
use Illuminate\Support\Facades\Validator;
class MenuService
{
protected static function tenantId(array $params): ?int
{
return $params['tenant_id'] ?? request()->attributes->get('tenant_id');
}
protected static function actorId(array $params): ?int
{
return $params['user_id'] ?? (request()->user()->id ?? null);
}
public static function index(array $params)
{
$tenantId = self::tenantId($params);
$q = DB::table('menus')->whereNull('deleted_at');
if (!is_null($tenantId)) {
$q->where(function ($w) use ($tenantId) {
$w->whereNull('tenant_id')->orWhere('tenant_id', $tenantId);
});
}
// 옵션: parent_id / is_active / hidden 필터
if (isset($params['parent_id'])) $q->where('parent_id', $params['parent_id']);
if (isset($params['is_active'])) $q->where('is_active', (int)$params['is_active']);
if (isset($params['hidden'])) $q->where('hidden', (int)$params['hidden']);
return $q->orderBy('parent_id')->orderBy('sort_order')->get();
}
public static function show(array $params)
{
$id = (int)($params['id'] ?? 0);
$tenantId = self::tenantId($params);
$q = DB::table('menus')->where('id', $id)->whereNull('deleted_at');
if (!is_null($tenantId)) {
$q->where(function ($w) use ($tenantId) {
$w->whereNull('tenant_id')->orWhere('tenant_id', $tenantId);
});
}
$row = $q->first();
throw_if(!$row, ValidationException::withMessages(['id' => 'Menu not found']));
return $row;
}
public static function store(array $params)
{
$tenantId = self::tenantId($params);
$userId = self::actorId($params);
$v = Validator::make($params, [
'parent_id' => ['nullable','integer'],
'name' => ['required','string','max:100'],
'slug' => ['nullable','string','max:150'],
'url' => ['nullable','string','max:255'],
'is_active' => ['nullable','boolean'],
'sort_order' => ['nullable','integer'],
'hidden' => ['nullable','boolean'],
'is_external' => ['nullable','boolean'],
'external_url' => ['nullable','string','max:255'],
'icon' => ['nullable','string','max:50'],
]);
$data = $v->validated();
// slug 유니크(테넌트 범위) 체크
if (!empty($data['slug'])) {
$exists = DB::table('menus')
->whereNull('deleted_at')
->when(!is_null($tenantId), fn($q)=>$q->where('tenant_id',$tenantId), fn($q)=>$q->whereNull('tenant_id'))
->where('slug',$data['slug'])
->exists();
if ($exists) {
throw ValidationException::withMessages(['slug'=>'이미 사용 중인 슬러그입니다.']);
}
}
$now = now();
$id = DB::table('menus')->insertGetId([
'tenant_id' => $tenantId,
'parent_id' => $data['parent_id'] ?? null,
'name' => $data['name'],
'slug' => $data['slug'] ?? null,
'url' => $data['url'] ?? null,
'is_active' => (int)($data['is_active'] ?? 1),
'sort_order' => (int)($data['sort_order'] ?? 0),
'hidden' => (int)($data['hidden'] ?? 0),
'is_external' => (int)($data['is_external'] ?? 0),
'external_url' => $data['external_url'] ?? null,
'icon' => $data['icon'] ?? null,
'created_at' => $now,
'updated_at' => $now,
'created_by' => $userId,
'updated_by' => $userId,
]);
return ['id' => $id];
}
public static function update(array $params)
{
$id = (int)($params['id'] ?? 0);
$tenantId = self::tenantId($params);
$userId = self::actorId($params);
$v = Validator::make($params, [
'parent_id' => ['nullable','integer'],
'name' => ['nullable','string','max:100'],
'slug' => ['nullable','string','max:150'],
'url' => ['nullable','string','max:255'],
'is_active' => ['nullable','boolean'],
'sort_order' => ['nullable','integer'],
'hidden' => ['nullable','boolean'],
'is_external' => ['nullable','boolean'],
'external_url' => ['nullable','string','max:255'],
'icon' => ['nullable','string','max:50'],
]);
$data = $v->validated();
// 대상 존재 확인 & 테넌트 범위
$exists = DB::table('menus')->where('id',$id)->whereNull('deleted_at')
->when(!is_null($tenantId), fn($q)=>$q->where('tenant_id',$tenantId), fn($q)=>$q->whereNull('tenant_id'))
->exists();
if (!$exists) throw ValidationException::withMessages(['id'=>'Menu not found']);
// slug 유니크(테넌트 범위) 체크
if (!empty($data['slug'])) {
$dup = DB::table('menus')->whereNull('deleted_at')
->when(!is_null($tenantId), fn($q)=>$q->where('tenant_id',$tenantId), fn($q)=>$q->whereNull('tenant_id'))
->where('slug',$data['slug'])->where('id','<>',$id)->exists();
if ($dup) throw ValidationException::withMessages(['slug'=>'이미 사용 중인 슬러그입니다.']);
}
$update = Arr::only($data, ['parent_id','name','slug','url','is_active','sort_order','hidden','is_external','external_url','icon']);
$update = array_filter($update, fn($v)=>!is_null($v));
$update['updated_at'] = now();
$update['updated_by'] = $userId;
DB::table('menus')->where('id',$id)->update($update);
return ['id' => $id];
}
public static function destroy(array $params)
{
$id = (int)($params['id'] ?? 0);
$tenantId = self::tenantId($params);
$userId = self::actorId($params);
$q = DB::table('menus')->where('id',$id)->whereNull('deleted_at');
$q = !is_null($tenantId)
? $q->where('tenant_id',$tenantId)
: $q->whereNull('tenant_id');
$row = $q->first();
if (!$row) throw ValidationException::withMessages(['id'=>'Menu not found']);
DB::table('menus')->where('id',$id)->update([
'deleted_at' => now(),
'deleted_by' => $userId,
]);
return ['id' => $id, 'deleted' => true];
}
/**
* 정렬 일괄 변경
* $params = [ ['id'=>10, 'sort_order'=>1], ... ]
*/
public static function reorder(array $params)
{
if (!is_array($params) || empty($params)) {
throw ValidationException::withMessages(['items'=>'유효한 정렬 목록이 필요합니다.']);
}
DB::transaction(function () use ($params) {
foreach ($params as $it) {
if (!isset($it['id'], $it['sort_order'])) continue;
DB::table('menus')->where('id',(int)$it['id'])->update([
'sort_order' => (int)$it['sort_order'],
'updated_at' => now(),
]);
}
});
return true;
}
/**
* 상태 토글
* 허용 필드: is_active / hidden / is_external
*/
public static function toggle(array $params)
{
$id = (int)($params['id'] ?? 0);
$userId = self::actorId($params);
$payload = array_filter([
'is_active' => isset($params['is_active']) ? (int)$params['is_active'] : null,
'hidden' => isset($params['hidden']) ? (int)$params['hidden'] : null,
'is_external' => isset($params['is_external']) ? (int)$params['is_external'] : null,
], fn($v)=>!is_null($v));
if (empty($payload)) {
throw ValidationException::withMessages(['toggle'=>'변경할 필드가 없습니다.']);
}
$payload['updated_at'] = now();
$payload['updated_by'] = $userId;
DB::table('menus')->where('id',$id)->update($payload);
return ['id' => $id];
}
}