where('tenant_id', $tenantId) ->where('guard_name', self::$guard) ->withCount(['permissions', 'users']); // 검색 필터 if ($q !== '') { $query->where(function ($w) use ($q) { $w->where('name', 'like', "%{$q}%") ->orWhere('description', 'like', "%{$q}%"); }); } // 숨김 상태 필터 if (isset($params['is_hidden'])) { $isHidden = filter_var($params['is_hidden'], FILTER_VALIDATE_BOOLEAN); $query->where('is_hidden', $isHidden); } $list = $query->orderByDesc('id') ->paginate($size, ['*'], 'page', $page); return $list; } /** 생성 */ public static function store(array $params = []) { $tenantId = (int) app('tenant_id'); $userId = app('api_user'); // Spatie 팀(테넌트) 컨텍스트 app(PermissionRegistrar::class)->setPermissionsTeamId($tenantId); $role = Role::create([ 'tenant_id' => $tenantId, 'guard_name' => self::$guard, 'name' => $params['name'], 'description' => $params['description'] ?? null, 'is_hidden' => $params['is_hidden'] ?? false, 'created_by' => $userId, ]); return $role->loadCount(['permissions', 'users']); } /** 단건 */ public static function show(int $id) { $tenantId = (int) app('tenant_id'); $role = Role::where('tenant_id', $tenantId) ->where('guard_name', self::$guard) ->withCount(['permissions', 'users']) ->find($id); if (! $role) { return ['error' => __('error.role.not_found'), 'code' => 404]; } return $role; } /** 수정 */ public static function update(int $id, array $params = []) { $tenantId = (int) app('tenant_id'); $userId = app('api_user'); $role = Role::where('tenant_id', $tenantId) ->where('guard_name', self::$guard) ->find($id); if (! $role) { return ['error' => __('error.role.not_found'), 'code' => 404]; } $updateData = $params; $updateData['updated_by'] = $userId; $role->fill($updateData)->save(); return $role->fresh()->loadCount(['permissions', 'users']); } /** 삭제 (Soft Delete) */ public static function destroy(int $id) { $tenantId = (int) app('tenant_id'); $userId = app('api_user'); $role = Role::where('tenant_id', $tenantId) ->where('guard_name', self::$guard) ->find($id); if (! $role) { return ['error' => __('error.role.not_found'), 'code' => 404]; } DB::transaction(function () use ($role, $userId) { // 권한 연결 해제 $role->permissions()->detach(); // Soft Delete $role->update(['deleted_by' => $userId]); $role->delete(); }); AccessService::bumpVersion($tenantId); app(PermissionRegistrar::class)->forgetCachedPermissions(); return 'success'; } /** 통계 조회 */ public static function stats() { $tenantId = (int) app('tenant_id'); $baseQuery = Role::where('tenant_id', $tenantId) ->where('guard_name', self::$guard); return [ 'total' => (clone $baseQuery)->count(), 'visible' => (clone $baseQuery)->where('is_hidden', false)->count(), 'hidden' => (clone $baseQuery)->where('is_hidden', true)->count(), 'with_users' => (clone $baseQuery)->has('users')->count(), ]; } /** 활성 역할 목록 (드롭다운용) */ public static function active() { $tenantId = (int) app('tenant_id'); return Role::where('tenant_id', $tenantId) ->where('guard_name', self::$guard) ->where('is_hidden', false) ->orderBy('name') ->get(['id', 'name', 'description']); } }