assertColleague($businessId, $otherUserId); $existing = ChatRoom::where('business_id', $businessId) ->where('type', 'direct') ->whereHas('members', fn ($q) => $q->where('users.id', $user->id)) ->whereHas('members', fn ($q) => $q->where('users.id', $otherUserId)) ->first(); if ($existing) { return $existing->load(['members', 'latestMessage.user']); } return DB::transaction(function () use ($businessId, $user, $otherUserId) { $room = ChatRoom::create([ 'business_id' => $businessId, 'type' => 'direct', 'created_by' => $user->id, ]); $room->members()->attach([$user->id, $otherUserId]); return $room->load(['members', 'latestMessage.user']); }); } public function createGroupRoom(int $businessId, User $user, string $name, array $memberIds): ChatRoom { $memberIds = array_values(array_unique(array_map('intval', array_merge($memberIds, [$user->id])))); foreach ($memberIds as $memberId) { $this->assertColleague($businessId, $memberId); } return DB::transaction(function () use ($businessId, $user, $name, $memberIds) { $room = ChatRoom::create([ 'business_id' => $businessId, 'type' => 'group', 'name' => $name, 'created_by' => $user->id, ]); $room->members()->attach($memberIds); return $room->load(['members', 'latestMessage.user']); }); } public function assertRoomMember(ChatRoom $room, User $user): void { if (! $room->members()->where('users.id', $user->id)->exists()) { throw ValidationException::withMessages(['room' => __('communication::lang.not_room_member')]); } } public function assertColleague(int $businessId, int $userId): void { $exists = User::where('business_id', $businessId)->where('id', $userId)->exists(); if (! $exists) { throw ValidationException::withMessages(['user_id' => __('communication::lang.user_not_in_business')]); } } public function addMember(ChatRoom $room, int $businessId, User $actor, int $memberId): ChatRoom { $this->assertRoomMember($room, $actor); if ($room->type !== 'group') { throw ValidationException::withMessages(['room' => __('communication::lang.group_only')]); } $this->assertColleague($businessId, $memberId); if (! $room->members()->where('users.id', $memberId)->exists()) { $room->members()->attach($memberId); } return $room->load(['members', 'latestMessage.user']); } public function removeMember(ChatRoom $room, User $actor, int $memberId): ChatRoom { $this->assertRoomMember($room, $actor); if ($room->type !== 'group') { throw ValidationException::withMessages(['room' => __('communication::lang.group_only')]); } if ($memberId !== $actor->id && (int) $room->created_by !== (int) $actor->id) { abort(403, 'Unauthorized action.'); } $room->members()->detach($memberId); return $room->load(['members', 'latestMessage.user']); } }