src/EventSubscriber/Tournament/PhaseEndedEventSubscriber.php line 31

Open in your IDE?
  1. <?php
  2. namespace App\EventSubscriber\Tournament;
  3. use App\Entity\Contest;
  4. use App\Entity\ContestPlayer;
  5. use App\Entity\Notification;
  6. use App\Entity\Phase;
  7. use App\Entity\Player;
  8. use App\Entity\Result;
  9. use App\Entity\Tournament;
  10. use App\Event\Tournament\Contest\ContestResultCreatedEvent as TournamentContestResultCreatedEvent;
  11. use App\Event\Tournament\PhaseEndedEvent;
  12. use App\Event\Tournament\TournamentEndedEvent;
  13. use App\Helper\PhaseHelper;
  14. use App\Message\CreateNotificationMessage;
  15. use DateTimeImmutable;
  16. use Doctrine\ORM\EntityManagerInterface;
  17. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  18. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  19. use Symfony\Component\Messenger\MessageBusInterface;
  20. class PhaseEndedEventSubscriber implements EventSubscriberInterface
  21. {
  22.     public function __construct(
  23.         private EntityManagerInterface $entityManager, private EventDispatcherInterface $eventDispatcher,
  24.         private MessageBusInterface $bus
  25.     ) {
  26.     }
  27.     public function onPhaseEndedEvent(PhaseEndedEvent $phaseEndedEvent): void
  28.     {
  29.         $endedPhase $phaseEndedEvent->getPhase();
  30.         $tournament $endedPhase->getTournament();
  31.         // loops through all phases to get the awaiting ones
  32.         $awaitingPhases $tournament->getPhases()->filter(function (Phase $phase) {
  33.             return $phase->getStatus() === Phase::AWAITING_START_STATUS;
  34.         });
  35.         // there is no awaiting phase anymore so it means the tournament was already on the last phase and it's now over
  36.         if ($awaitingPhases->isEmpty()) {
  37.             $tournament
  38.                 ->setStatus(Tournament::ENDED_STATUS)
  39.                 ->setEndedAt(new DateTimeImmutable())
  40.             ;
  41.             $playerIdsCollection $tournament->getPlayers()->map(function (Player $player) {
  42.                 return $player->getId();
  43.             });
  44.             $this->entityManager->flush();
  45.             // send notification to all player when match is finished
  46.             $this->bus->dispatch(new CreateNotificationMessage(
  47.                 $playerIdsCollection->toArray(),
  48.                 Notification::TOURNAMENT_ENDED,
  49.                 sprintf(
  50.                     'Tournoi terminé : %s !',
  51.                     $tournament->getName()
  52.                 ),
  53.                 ['tournamentId' => $tournament->getId()]
  54.             ));
  55.             $this->eventDispatcher->dispatch(new TournamentEndedEvent($tournament));
  56.             return;
  57.         }
  58.         $tournament->setCurrentPhase($awaitingPhases->first());
  59.         $players null;
  60.         // gets the winner of each contests of this phase
  61.         foreach ($endedPhase->getContests() as $contest) {
  62.             if ($contest->getWinner() !== null) {
  63.                 $players[] = $contest->getWinner();
  64.             }
  65.         }
  66.         // No player has played this phase
  67.         if ($players === null) {
  68.             $tournament
  69.                 ->setStatus(Tournament::CANCELLED_STATUS)
  70.                 ->setEndedAt(new DateTimeImmutable())
  71.             ;
  72.             $this->entityManager->flush();
  73.             return;
  74.         }
  75.         PhaseHelper::generatePhaseContests($tournament->getCurrentPhase(), $players);
  76.         // filters the contests that one have one player
  77.         $contests $tournament->getCurrentPhase()->getContests()->filter(function (Contest $contest) {
  78.             return $contest->getContestPlayers()->count() === 1;
  79.         });
  80.         // loops through all contests that only have one player to make them win automatically
  81.         foreach ($contests as $contest) {
  82.             /** @var ContestPlayer $contestPlayer */
  83.             $contestPlayer $contest->getContestPlayers()->first();
  84.             $player $contestPlayer->getPlayer();
  85.             $player->setXp(
  86.                 $player->getXp() + $contestPlayer->getXpToEarn()
  87.             );
  88.             $result = (new Result())
  89.                 ->setScore(0)
  90.                 ->setXp($contestPlayer->getXpToEarn())
  91.                 ->setPlayer($player)
  92.             ;
  93.             $contest->addResult($result);
  94.             $this->entityManager->flush();
  95.             // dispatches the contest result created event
  96.             $this->eventDispatcher->dispatch(new TournamentContestResultCreatedEvent($contest$result));
  97.         }
  98.         // starts the phase
  99.         $tournament
  100.             ->getCurrentPhase()
  101.             ->setStatus(Phase::STARTED_STATUS)
  102.             ->setStartedAt(new DateTimeImmutable())
  103.         ;
  104.         /** @var Phase[] $upcomingPhases */
  105.         $upcomingPhases $tournament->getPhases()->filter(function (Phase $phase) use ($tournament) {
  106.             return $phase->getStatus() === Phase::AWAITING_START_STATUS && $phase !== $tournament->getCurrentPhase();
  107.         });
  108.         $previousPhase null;
  109.         // loops through all upcoming phases and changes their start/end date
  110.         foreach ($upcomingPhases as $upcomingPhase) {
  111.             $previousPhase $previousPhase ?? $tournament->getCurrentPhase();
  112.             $startDate $previousPhase->getEndDate();
  113.             $upcomingPhase->setStartDate($startDate);
  114.             $previousPhase $upcomingPhase;
  115.         }
  116.         foreach ($players as $player) {
  117.             $player->addNotification(
  118.                 (new Notification())
  119.                     ->setType(Notification::TOURNAMENT_PHASE_STARTED)
  120.                     ->setMessage(sprintf(
  121.                         '%s : Une nouvelle phase commence !',
  122.                         $tournament->getName()
  123.                     ))
  124.                     ->setExtraData(['tournamentId' => $tournament->getId()])
  125.             );
  126.         }
  127.         $this->entityManager->flush();
  128.     }
  129.     public static function getSubscribedEvents(): array
  130.     {
  131.         return [
  132.             PhaseEndedEvent::class => 'onPhaseEndedEvent',
  133.         ];
  134.     }
  135. }