$roomPlayers */ public function handle(User $user, array $roomPlayers): void { foreach ($roomPlayers as $roomId => $playerId) { if (! is_string($roomId) || ! is_numeric($playerId)) { continue; } DB::transaction(function () use ($user, $roomId, $playerId): void { $room = Room::query()->lockForUpdate()->find($roomId); if ($room === null || $room->owner_id !== null) { return; } $moderator = $room->players() ->whereKey((int) $playerId) ->where('is_moderator', true) ->where(function ($query) use ($user): void { $query->whereNull('user_id')->orWhere('user_id', $user->id); }) ->lockForUpdate() ->first(); if ($moderator === null) { return; } $existingPlayer = $room->players() ->where('user_id', $user->id) ->whereKeyNot($moderator->id) ->lockForUpdate() ->first(); if ($existingPlayer !== null) { $this->mergePlayerIntoModerator($existingPlayer, $moderator); } $moderator->update(['user_id' => $user->id]); $room->update(['owner_id' => $user->id]); }); } } private function mergePlayerIntoModerator(Player $source, Player $moderator): void { $source->votes() ->orderBy('updated_at') ->each(function (Vote $vote) use ($moderator): void { $targetVote = $moderator->votes() ->where('room_id', $vote->room_id) ->where('round', $vote->round) ->first(); if ($targetVote === null || $vote->updated_at->greaterThanOrEqualTo($targetVote->updated_at)) { Vote::updateOrCreate( [ 'player_id' => $moderator->id, 'room_id' => $vote->room_id, 'round' => $vote->round, ], ['value' => $vote->value], ); } }); $source->delete(); } }