<?php
namespace App\EventSubscriber\Contest;
use App\Entity\Notification;
use App\Entity\Transaction;
use App\Event\Contest\ContestCancelledEvent;
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 ContestCancelledEventSubscriber implements EventSubscriberInterface
{
public function __construct(
private EntityManagerInterface $entityManager, private PlayerHelper $playerHelper,
private BetConfigRepository $betConfigRepository, private NotificationRepository $notificationRepository,
private TransactionFactory $transactionFactory
) {
}
public static function getSubscribedEvents(): array
{
return [
ContestCancelledEvent::class => 'onContestCancelled',
];
}
public function onContestCancelled(ContestCancelledEvent $contestCancelledEvent): void
{
$contest = $contestCancelledEvent->getContest();
$contestCreator = $contest->getCreatedBy();
// refunds the contest's creator if he is the one who cancelled it
if ($contestCancelledEvent->isTriggeredByCreator()) {
$this->transactionFactory
->forPlayer($contestCreator)
->givePs($contest->getBet())
->because(Transaction::REFUNDED_PS_DUE_TO_CONTEST_CANCELLATION_TYPE)
->save()
;
$this->entityManager->flush();
return;
}
// updates the contest creator activity and notifies him if the contest has been cancelled because he hasn't scored on time
if (!ContestHelper::hasScored($contest, $contestCreator)) {
$this->playerHelper->updateActivity($contestCreator, ContestCancelledEvent::class);
$contestCreator->addNotification(
(new Notification())
->setType(Notification::CONTEST_CANCELLED_TYPE)
->setContest($contest)
->setMessage(sprintf('Votre match de %s a été annulé pour cause d\'inactivité de votre part.', $contest->getGame()->getName()))
);
$this->entityManager->flush();
return;
}
// Updates all invite notifications for this Contest to "archived"
$this->notificationRepository->updateBy(
['archived' => true],
[
'contest' => $contest,
'type' => Notification::CONTEST_INVITATION_TYPE,
]
);
// loops through all opponents of this contest who has not scored, alters their activity
foreach ($contest->getContestPlayers() as $contestPlayer) {
$player = $contestPlayer->getPlayer();
// we don't need to check if the current player is an opponent or the creator here because we already checked above
// so we are sure that we are only getting opponents who have not scored
if (ContestHelper::hasScored($contest, $player)) {
continue;
}
$this->playerHelper->updateActivity($player, ContestCancelledEvent::class);
$player->addNotification(
(new Notification())
->setType(Notification::CONTEST_CANCELLED_TYPE)
->setContest($contest)
->setMessage(sprintf('Votre match de %s a été annulé pour cause d\'inactivité de votre part.', $contest->getGame()->getName()))
);
}
// the contest's creator automatically becomes the winner as his opponents are inactive
$winner = $contestCreator;
$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()
;
$winner->addNotification(
(new Notification())
->setContest($contest)
->setType(Notification::CONTEST_CLOSED_TYPE)
->setMessage(sprintf('%s, vous avez gagné un match.', $winner->getUser()->getUsername()))
);
$this->entityManager->flush();
}
}