Add tournament list

This commit is contained in:
Aleksandr Zaitsev 2024-03-11 17:52:08 +02:00
parent f02e3d9319
commit d58dfd022d
14 changed files with 103 additions and 37 deletions

View File

@ -6,6 +6,7 @@ use App\Repository\TournamentRepository;
use App\Service\PlayOffGameService;
use App\Service\QualifyingGameService;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
@ -18,6 +19,21 @@ class TournamentController extends AbstractController
private readonly PlayOffGameService $playOffGameService,
) {}
#[Route(path: '/', name: 'tournament_list_get', methods: ['GET'])]
public function getTournamentList(Request $request)
{
$page = $request->get('page') ?? 0;
return $this->render(
'index.html.twig',
[
'tournamentList' => $this->tournamentRepository->getTournamentList($page),
'tournamentCount' => $this->tournamentRepository->getTotalTournament(),
'page' => $page,
'tournamentPerPage' => TournamentRepository::TOURNAMENT_PER_PAGE
]
);
}
#[Route(path: '/tournament/{tournamentId}', name: 'tournament_get', methods: ['GET'])]
public function getTournament($tournamentId): Response
{
@ -38,4 +54,10 @@ class TournamentController extends AbstractController
['tournament' => $tournament]
);
}
#[Route(path: '/tournament', name: 'tournament_create', methods: ['POST'])]
public function createTournament()
{
return $this->redirectToRoute('tournament_list');
}
}

View File

@ -34,7 +34,7 @@ class TournamentGeneratorController extends AbstractController
private PlayOffGameService $playOffGameService
) {}
#[Route(path: '/', name: 'tournament_generate', methods: ['get'])]
#[Route(path: '/generate', name: 'tournament_generate', methods: ['get'])]
public function index(Request $request): Response
{
$faker = Factory::create();

View File

@ -25,7 +25,7 @@ class Division
private ?string $id = null;
public function __construct(
#[ORM\Column(type: Types::STRING, length: 255 ,nullable: false)]
#[ORM\Column(type: Types::STRING, length: 255, nullable: false)]
private readonly string $title,
#[ORM\ManyToOne(targetEntity: Tournament::class, cascade: ['persist'], inversedBy: 'divisionList')]
@ -33,13 +33,13 @@ class Division
private readonly Tournament $tournament,
#[ORM\OneToMany(targetEntity: Player::class, mappedBy: 'division')]
private Collection $playerList = new ArrayCollection(),
private Collection $playerList = new ArrayCollection(),
/**
* @var Collection<int, Game>
*/
#[ORM\OneToMany(targetEntity: QualifyingGame::class, mappedBy: 'division')]
private Collection $gameList = new ArrayCollection(),
private Collection $gameList = new ArrayCollection(),
#[ORM\Column(type: Types::DATETIME_IMMUTABLE, nullable: false)]
private readonly DateTimeImmutable $createdAt = new DateTimeImmutable(),
@ -128,7 +128,7 @@ class Division
{
$playerIdList = [];
foreach ($players as $player) $playerIdList[] = $player->getId();
$gameList = $this->gameList->filter(
$gameList = $this->gameList->filter(
function (QualifyingGame $qualifyingGame) use ($playerIdList) {
$scorePlayerIdList = [];
foreach ($qualifyingGame->getScoreList() as $scoreList) {
@ -164,7 +164,7 @@ class Division
$totalScore = 0;
foreach ($this->gameList as $game) {
foreach ($game->getScoreList() as $score) {
if(is_null($score->getScore())) continue 2;
if (is_null($score->getScore())) continue 2;
}
$criteria = new Criteria();
$criteria->orderBy(['score' => Order::Descending])

View File

@ -2,12 +2,16 @@
namespace App\Entity\Game;
use App\Enum\GameStatus;
use App\Entity\Player;
use Doctrine\Common\Collections\Collection;
use DateTimeImmutable;
interface GameInterface
{
/**
* @return string|null
*/
public function getId(): ?string;
/**
* @return DateTimeImmutable
*/
@ -17,4 +21,10 @@ interface GameInterface
* @return Collection<int, GameScore>
*/
public function getScoreList(): Collection;
/**
* @param Player $player
* @return GameScore|null
*/
public function getPlayerScore(Player $player): ?GameScore;
}

View File

@ -26,9 +26,7 @@ class GameScore
#[ORM\Column(nullable: true)]
private ?int $score = null,
) {
}
) {}
/**
* @return string|null

View File

@ -4,7 +4,6 @@ namespace App\Entity\Game;
use App\Entity\Player;
use App\Entity\Tournament;
use App\Enum\GameStatus;
use App\Repository\Game\QualifyingGameRepository;
use DateTimeImmutable;
use Doctrine\Common\Collections\Collection;

View File

@ -22,10 +22,10 @@ class QualifyingGame implements GameInterface
public function __construct(
#[ORM\ManyToOne(cascade: ['remove'])]
private Division $division,
private readonly Division $division,
#[ORM\OneToOne(cascade: ['remove', 'persist'])]
private Game $game,
private readonly Game $game,
) {
$this->division->addGame($this);
}

View File

@ -2,9 +2,7 @@
namespace App\Entity;
use App\Entity\Game\Game;
use App\Entity\Game\PlayOffGame;
use App\Enum\TournamentStatus;
use App\Repository\TournamentRepository;
use DateTimeImmutable;
use Doctrine\Common\Collections\ArrayCollection;

View File

@ -4,8 +4,8 @@ namespace App\Enum;
enum GameStatus: string
{
case NEW = 'new';
case ACTIVE = 'active';
case ENDED = 'ended';
case new = 'new';
case active = 'active';
case ended = 'ended';
}

View File

@ -1,9 +0,0 @@
<?php
namespace App\Enum;
enum GameType: string
{
case TOURNAMENT = 'tournament';
case DIVISION = 'division';
}

View File

@ -4,6 +4,8 @@ namespace App\Repository;
use App\Entity\Tournament;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\Persistence\ManagerRegistry;
/**
@ -16,6 +18,7 @@ use Doctrine\Persistence\ManagerRegistry;
*/
class TournamentRepository extends ServiceEntityRepository
{
public const TOURNAMENT_PER_PAGE = 10;
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Tournament::class);
@ -27,4 +30,24 @@ class TournamentRepository extends ServiceEntityRepository
$this->getEntityManager()->flush();
return $tournamentEntity;
}
/**
* @param int $page
* @return Collection<int, Tournament>
*/
public function getTournamentList(int $page = 0): Collection
{
$query = $this->createQueryBuilder('t')
->setFirstResult(self::TOURNAMENT_PER_PAGE * $page)
->setMaxResults(self::TOURNAMENT_PER_PAGE);
return new ArrayCollection($query->getQuery()->getResult());
}
/**
* @return int
*/
public function getTotalTournament(): int
{
return count($this->findAll());
}
}

View File

@ -11,7 +11,7 @@
<body >
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container">
<a class="navbar-brand" href="#">Tournament</a>
<a class="navbar-brand" href="/">Tournament</a>
</div>
</nav>
{% block body %}{% endblock %}

View File

@ -2,19 +2,39 @@
{% block body %}
<div class="container">
<div class="text-center mt-5">
<form action="/tournament" method="post">
<form action="/tournament" method="post" style="display: none">
<fieldset>
<legend>Create tournament</legend>
<div class="mb-3">
<label for="title" class="form-label">Tournament title</label>
<input type="text" id="title" name="title" class="form-control" placeholder="Enter your tournament title">
<input type="text" id="title" name="title" class="form-control"
placeholder="Enter your tournament title">
</div>
<button type="submit" class="btn btn-primary">Generate tournament</button>
<button type="submit" class="btn btn-primary">Create tournament</button>
</fieldset>
</form>
<div class="text-center mt-5"><a href="/generate" class="btn btn-primary">Generate new prefilled
tournament</a></div>
</div>
<div class="text-center mt-5">
tournament list
{% if tournamentCount > 0 %}
<div>There are {{ tournamentCount }} created tournaments.</div>
{% for tournament in tournamentList %}
<div>
<a href="{{ path('tournament_get', { tournamentId: tournament.getId() }) }}">{{ tournament.getTitle() }}</a>
</div>
{% endfor %}
{% if page > 0 %}
<a href="{{ path('tournament_list_get', { page: page - 1 }) }}">Previous</a>
{% endif %}
{% if page + 1 < tournamentCount/tournamentPerPage and tournamentList.count() >= tournamentPerPage %}
<a href="{{ path('tournament_list_get', { page: page + 1 }) }}">Next</a>
{% endif %}
{% else %}
<div>No tournaments have been created yet.</div>
{% endif %}
</div>
</div>
{% endblock %}

View File

@ -1,7 +1,6 @@
{% extends "base.html.twig" %}
{% block body %}
<div class="container">
<div class="text-center mt-5"><a href="/" class="button">Generate new Tournament</a> </div>
<div class="text-center mt-5">
<h1>Tournament {{ tournament.getTitle() }}</h1>
</div>
@ -44,7 +43,13 @@
<div class="text-center mt-5">
<h1>Play off</h1>
{% for stage, stageGameList in tournament.getPlayOffStageList() %}
<h3>1 / {{ stage }}</h3>
<h3>
{% if stage > 1 %}
1 / {{ stage }}
{% else %}
Final
{% endif %}
</h3>
{% for index, playOffStageGame in stageGameList %}
<table class="table">
<thead>
@ -64,10 +69,10 @@
{% endfor %}
</div>
<div class="text-center mt-5">
<h1>Winner</h1>
<div class="text-center mt-5 mb-5">
<h1>Tournament Winner</h1>
{% set winner = tournament.getStageWinnerList(1) %}
<h2>{{ winner.first().getPlayer().getTitle() }}</h2>
<h1>{{ winner.first().getPlayer().getTitle() }}</h1>
</div>
</div>
{% endblock %}