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'); $v = Validator::make($params, [ 'name' => [ 'required', 'string', 'max:100', Rule::unique('roles', 'name')->where(fn ($q) => $q ->where('tenant_id', $tenantId) ->where('guard_name', self::$guard)), ], 'description' => 'nullable|string|max:255', 'is_hidden' => 'sometimes|boolean', ]); if ($v->fails()) { return ['error' => $v->errors()->first(), 'code' => 422]; } // Spatie 팀(테넌트) 컨텍스트 app(PermissionRegistrar::class)->setPermissionsTeamId($tenantId); $role = Role::create([ 'tenant_id' => $tenantId, 'guard_name' => self::$guard, 'name' => $v->validated()['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' => '역할을 찾을 수 없습니다.', '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' => '역할을 찾을 수 없습니다.', 'code' => 404]; } $v = Validator::make($params, [ 'name' => [ 'sometimes', 'string', 'max:100', Rule::unique('roles', 'name') ->where(fn ($q) => $q->where('tenant_id', $tenantId)->where('guard_name', self::$guard)) ->ignore($role->id), ], 'description' => 'sometimes|nullable|string|max:255', 'is_hidden' => 'sometimes|boolean', ]); if ($v->fails()) { return ['error' => $v->errors()->first(), 'code' => 422]; } $updateData = $v->validated(); $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' => '역할을 찾을 수 없습니다.', 'code' => 404]; } DB::transaction(function () use ($role, $userId) { // 권한 연결 해제 $role->permissions()->detach(); // Soft Delete $role->update(['deleted_by' => $userId]); $role->delete(); }); 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']); } }