Files
scrum-poker-internal/app/Actions/Rooms/ClaimGuestRooms.php
T

84 lines
2.6 KiB
PHP

<?php
namespace App\Actions\Rooms;
use App\Models\Player;
use App\Models\Room;
use App\Models\User;
use App\Models\Vote;
use Illuminate\Support\Facades\DB;
class ClaimGuestRooms
{
/**
* @param array<array-key, mixed> $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();
}
}