<?php
namespace App\EventSubscriber\Contest;
use App\Entity\Contest;
use App\Entity\Notification;
use App\Entity\Transaction;
use App\Event\Contest\ContestResultCreatedEvent;
use App\Factory\TransactionFactory;
use App\Helper\ContestHelper;
use App\Helper\PlayerHelper;
use App\Repository\BetConfigRepository;
use App\Repository\NotificationRepository;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class ContestResultCreatedEventSubscriber implements EventSubscriberInterface
{
public function __construct(
private EntityManagerInterface $entityManager, private BetConfigRepository $betConfigRepository,
private PlayerHelper $playerHelper, private NotificationRepository $notificationRepository,
private TransactionFactory $transactionFactory
) {
}
public static function getSubscribedEvents(): array
{
return [
ContestResultCreatedEvent::class => 'onContestResultCreated',
];
}
public function onContestResultCreated(ContestResultCreatedEvent $contestResultCreatedEvent): void
{
$contest = $contestResultCreatedEvent->getContest();
$result = $contestResultCreatedEvent->getResult();
$player = $result->getPlayer();
$this->playerHelper->updateActivity($player, ContestResultCreatedEvent::class);
// removes the bet PS from the player who just scored (we already removed for the contest creator earlier) and updates its activity
if ($player !== $contest->getCreatedBy()) {
$this->transactionFactory
->forPlayer($player)
->takePs($contest->getBet())
->because(Transaction::CONTEST_RESULT_CREATED_TYPE)
->save()
;
}
// updates the player's xp
$player->setXp($player->getXp() + $result->getXp());
if (ContestHelper::hasAllPlayersScored($contest)) {
// updates all invite notifications for this Contest to "archived"
$this->notificationRepository->updateBy(
['archived' => true],
[
'contest' => $contest,
'type' => Notification::CONTEST_INVITATION_TYPE,
]
);
// gives back to all players their "bet" if the contest has even results
if (ContestHelper::hasEvenResults($contest)) {
// notifies the players and refunds their bet
foreach ($contest->getContestPlayers() as $contestPlayer) {
$player = $contestPlayer->getPlayer();
$this->transactionFactory
->forPlayer($player)
->givePs($contest->getBet())
->because(Transaction::REFUNDED_PS_DUE_TO_CONTEST_EVEN_RESULTS_TYPE)
->save()
;
$player
->addNotification(
(new Notification())
->setContest($contest)
->setType(Notification::CONTEST_CLOSED_TYPE)
->setMessage(
sprintf(
'Le match de %s s\'est terminé par un match nul et votre mise vous a été remboursée.',
$contest->getGame()->getName()
)
)
)
;
}
} else {
$highestResult = ContestHelper::findHighestResult($contest);
$winner = $highestResult->getPlayer();
$betConfig = $this->betConfigRepository->findOneBy([
'initialValue' => $contest->getBet(),
]);
$contest->setWinner($winner);
$winner
->setXp($winner->getXp() + ContestHelper::getXpToEarn($contest, $winner))
;
$this->transactionFactory
->forPlayer($winner)
->givePs($betConfig->getWinningValue())
->because(Transaction::CONTEST_WINNER_TYPE)
->save()
;
// notifies the players and updates their PS
foreach ($contest->getContestPlayers() as $contestPlayer) {
$player = $contestPlayer->getPlayer();
if ($player === $winner) {
$message = sprintf(
'Vous avez gagné le match de %s et vous remportez %s PS.',
$contest->getGame()->getName(),
$betConfig->getWinningValue()
);
} else {
$message = sprintf(
'Vous avez perdu le match de %s.',
$contest->getGame()->getName()
);
}
$player->addNotification(
(new Notification())
->setContest($contest)
->setType(Notification::CONTEST_CLOSED_TYPE)
->setMessage($message)
);
}
}
// all players have scored so we close the contest
$contest->setStatus(Contest::CLOSED_STATUS);
} else {
$contest->setStatus(Contest::WAITING_SCORES_STATUS);
// creates notifications
foreach ($contest->getContestPlayers() as $contestPlayer) {
$player = $contestPlayer->getPlayer();
// notifies all players except the creator
if ($contest->getCreatedBy() === $player) {
continue;
}
$message = sprintf(
'Le joueur %s vous a défié sur un %s',
/* @phpstan-ignore-next-line */
$contest->getCreatedBy()->getUser()->getUsername(),
$contest->getGame()->getName()
);
$player->addNotification(
(new Notification())
->setType(Notification::CONTEST_INVITATION_TYPE)
->setContest($contest)
->setMessage($message)
);
}
}
$this->entityManager->flush();
}
}