Files
scrum-poker-internal/app/Services/Rooms/RoomParticipationService.php
T

105 lines
2.8 KiB
PHP

<?php
namespace App\Services\Rooms;
use App\Enums\RoomStateChange;
use App\Events\RoomStateChanged;
use App\Models\Player;
use App\Models\Room;
use App\Models\User;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\ValidationException;
class RoomParticipationService
{
public function __construct(
private readonly RoomRealtimeStateService $realtimeState,
) {}
public function findByJoinCode(string $joinCode): ?Room
{
if ($joinCode === '') {
return null;
}
return Room::query()
->where('join_code', $joinCode)
->first();
}
public function findExistingPlayer(
Room $room,
?User $user,
mixed $sessionPlayerId,
): ?Player {
if ($user !== null) {
return $room->players()
->where('user_id', $user->id)
->first();
}
if (! is_numeric($sessionPlayerId)) {
return null;
}
return $room->players()->find((int) $sessionPlayerId);
}
/**
* @param array{join_code: string, player_name: string} $data
* @param array<string, mixed> $sessionPlayerIds
* @return array{Room, Player}
*/
public function join(array $data, ?User $user, array $sessionPlayerIds): array
{
[$room, $player] = DB::transaction(function () use ($data, $user, $sessionPlayerIds): array {
$room = Room::query()
->where('join_code', $data['join_code'])
->lockForUpdate()
->firstOrFail();
if ($room->isClosed()) {
throw ValidationException::withMessages([
'join_code' => 'Dieser Raum ist geschlossen.',
]);
}
$player = $this->findExistingPlayer(
$room,
$user,
$sessionPlayerIds[$room->id] ?? null,
);
if ($player === null) {
$player = $room->players()->create([
'user_id' => $user?->id,
'name' => $data['player_name'],
'is_moderator' => false,
'last_seen_at' => now(),
]);
} else {
$player->update([
'last_seen_at' => now(),
'inactive_at' => null,
]);
}
$room->update([
'last_activity_at' => now(),
'state_version' => $room->state_version + 1,
]);
return [$room, $player];
});
RoomStateChanged::dispatch(
$room->id,
$room->state_version,
RoomStateChange::PlayerJoined,
$this->realtimeState->for($room),
);
return [$room, $player];
}
}