validated(); $user = $request->user(); [$room, $player] = DB::transaction(function () use ($request, $validated, $user): array { $room = Room::query() ->where('join_code', $validated['join_code']) ->lockForUpdate() ->firstOrFail(); if ($room->isClosed()) { throw ValidationException::withMessages([ 'join_code' => 'Dieser Raum ist geschlossen.', ]); } $player = $this->existingPlayer($request, $room); if ($player === null) { $player = $room->players()->create([ 'user_id' => $user?->id, 'name' => $validated['player_name'], 'is_moderator' => false, 'last_seen_at' => now(), ]); } else { $player->update(['last_seen_at' => now()]); } $room->update([ 'last_activity_at' => now(), 'state_version' => $room->state_version + 1, ]); return [$room, $player]; }); $request->session()->put( "room_players.{$room->id}", $player->id, ); RoomStateChanged::dispatch( $room->id, $room->state_version, RoomStateChange::PlayerJoined, ); return to_route('room.show', $room); } private function existingPlayer(JoinRoomRequest $request, Room $room): ?Player { if ($request->user() !== null) { return $room->players() ->where('user_id', $request->user()->id) ->first(); } $playerId = $request->session()->get("room_players.{$room->id}"); return is_numeric($playerId) ? $room->players()->find((int) $playerId) : null; } }