This commit is contained in:
2025-03-04 08:15:50 +01:00
parent d337ce86fb
commit 451d117d9e
83 changed files with 5528 additions and 262 deletions

124
src/Entity/Answer.php Normal file
View File

@@ -0,0 +1,124 @@
<?php
declare(strict_types=1);
namespace App\Entity;
use App\Repository\AnswerRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator;
use Symfony\Bridge\Doctrine\Types\UuidType;
use Symfony\Component\Uid\Uuid;
#[ORM\Entity(repositoryClass: AnswerRepository::class)]
class Answer
{
#[ORM\Id]
#[ORM\Column(type: UuidType::NAME)]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\CustomIdGenerator(class: UuidGenerator::class)]
private Uuid $id;
#[ORM\ManyToOne(inversedBy: 'answers')]
#[ORM\JoinColumn(nullable: false)]
private Question $question;
/** @var Collection<int, Candidate> */
#[ORM\ManyToMany(targetEntity: Candidate::class, inversedBy: 'answersOnCandidate')]
private Collection $candidates;
/** @var Collection<int, GivenAnswer> */
#[ORM\OneToMany(targetEntity: GivenAnswer::class, mappedBy: 'answer', orphanRemoval: true)]
private Collection $givenAnswers;
public function __construct(
#[ORM\Column(length: 255)]
private string $text,
#[ORM\Column]
private bool $isRightAnswer = false,
) {
$this->candidates = new ArrayCollection();
$this->givenAnswers = new ArrayCollection();
}
public function getId(): Uuid
{
return $this->id;
}
public function getText(): string
{
return $this->text;
}
public function setText(string $text): static
{
$this->text = $text;
return $this;
}
public function getQuestion(): Question
{
return $this->question;
}
public function setQuestion(Question $question): static
{
$this->question = $question;
return $this;
}
public function isRightAnswer(): ?bool
{
return $this->isRightAnswer;
}
public function setRightAnswer(bool $isRightAnswer): static
{
$this->isRightAnswer = $isRightAnswer;
return $this;
}
/** @return Collection<int, Candidate> */
public function getCandidates(): Collection
{
return $this->candidates;
}
public function addCandidate(Candidate $candidate): static
{
if (!$this->candidates->contains($candidate)) {
$this->candidates->add($candidate);
}
return $this;
}
public function removeCandidate(Candidate $candidate): static
{
$this->candidates->removeElement($candidate);
return $this;
}
/** @return Collection<int, GivenAnswer> */
public function getGivenAnswers(): Collection
{
return $this->givenAnswers;
}
public function addGivenAnswer(GivenAnswer $givenAnswer): static
{
if (!$this->givenAnswers->contains($givenAnswer)) {
$this->givenAnswers->add($givenAnswer);
$givenAnswer->setAnswer($this);
}
return $this;
}
}

140
src/Entity/Candidate.php Normal file
View File

@@ -0,0 +1,140 @@
<?php
declare(strict_types=1);
namespace App\Entity;
use App\Helpers\Base64;
use App\Repository\CandidateRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator;
use Symfony\Bridge\Doctrine\Types\UuidType;
use Symfony\Component\Uid\Uuid;
#[ORM\Entity(repositoryClass: CandidateRepository::class)]
class Candidate
{
#[ORM\Id]
#[ORM\Column(type: UuidType::NAME, unique: true)]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\CustomIdGenerator(class: UuidGenerator::class)]
private ?Uuid $id = null;
#[ORM\ManyToOne(inversedBy: 'candidates')]
#[ORM\JoinColumn(nullable: false)]
private Season $season;
/** @var Collection<int, Answer> */
#[ORM\ManyToMany(targetEntity: Answer::class, mappedBy: 'candidates')]
private Collection $answersOnCandidate;
/** @var Collection<int, GivenAnswer> */
#[ORM\OneToMany(targetEntity: GivenAnswer::class, mappedBy: 'candidate', orphanRemoval: true)]
private Collection $givenAnswers;
/** @var Collection<int, Correction> */
#[ORM\OneToMany(targetEntity: Correction::class, mappedBy: 'candidate', orphanRemoval: true)]
private Collection $corrections;
public function __construct(
#[ORM\Column(length: 16)]
private string $name,
) {
$this->answersOnCandidate = new ArrayCollection();
$this->givenAnswers = new ArrayCollection();
$this->corrections = new ArrayCollection();
}
public function getId(): ?Uuid
{
return $this->id;
}
public function getSeason(): Season
{
return $this->season;
}
public function setSeason(Season $season): static
{
$this->season = $season;
return $this;
}
public function getName(): string
{
return $this->name;
}
public function setName(string $name): static
{
$this->name = $name;
return $this;
}
/** @return Collection<int, Answer> */
public function getAnswersOnCandidate(): Collection
{
return $this->answersOnCandidate;
}
public function addAnswersOnCandidate(Answer $answersOnCandidate): static
{
if (!$this->answersOnCandidate->contains($answersOnCandidate)) {
$this->answersOnCandidate->add($answersOnCandidate);
$answersOnCandidate->addCandidate($this);
}
return $this;
}
public function removeAnswersOnCandidate(Answer $answersOnCandidate): static
{
if ($this->answersOnCandidate->removeElement($answersOnCandidate)) {
$answersOnCandidate->removeCandidate($this);
}
return $this;
}
/** @return Collection<int, GivenAnswer> */
public function getGivenAnswers(): Collection
{
return $this->givenAnswers;
}
public function addGivenAnswer(GivenAnswer $givenAnswer): static
{
if (!$this->givenAnswers->contains($givenAnswer)) {
$this->givenAnswers->add($givenAnswer);
$givenAnswer->setCandidate($this);
}
return $this;
}
/** @return Collection<int, Correction> */
public function getCorrections(): Collection
{
return $this->corrections;
}
public function addCorrection(Correction $correction): static
{
if (!$this->corrections->contains($correction)) {
$this->corrections->add($correction);
$correction->setCandidate($this);
}
return $this;
}
public function getNameHash(): string
{
return Base64::base64_url_encode($this->name);
}
}

74
src/Entity/Correction.php Normal file
View File

@@ -0,0 +1,74 @@
<?php
declare(strict_types=1);
namespace App\Entity;
use App\Repository\CorrectionRepository;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator;
use Symfony\Bridge\Doctrine\Types\UuidType;
use Symfony\Component\Uid\Uuid;
#[ORM\Entity(repositoryClass: CorrectionRepository::class)]
#[ORM\UniqueConstraint(columns: ['candidate_id', 'quiz_id'])]
class Correction
{
#[ORM\Id]
#[ORM\Column(type: UuidType::NAME, unique: true)]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\CustomIdGenerator(class: UuidGenerator::class)]
private ?Uuid $id = null;
#[ORM\ManyToOne(inversedBy: 'corrections')]
#[ORM\JoinColumn(nullable: false)]
private Candidate $candidate;
#[ORM\ManyToOne(inversedBy: 'corrections')]
#[ORM\JoinColumn(nullable: false)]
private Quiz $quiz;
#[ORM\Column]
private float $amount = 0;
public function getId(): ?Uuid
{
return $this->id;
}
public function getCandidate(): Candidate
{
return $this->candidate;
}
public function setCandidate(Candidate $candidate): static
{
$this->candidate = $candidate;
return $this;
}
public function getQuiz(): Quiz
{
return $this->quiz;
}
public function setQuiz(Quiz $quiz): static
{
$this->quiz = $quiz;
return $this;
}
public function getAmount(): ?float
{
return $this->amount;
}
public function setAmount(float $amount): static
{
$this->amount = $amount;
return $this;
}
}

View File

@@ -0,0 +1,91 @@
<?php
declare(strict_types=1);
namespace App\Entity;
use App\Repository\GivenAnswerRepository;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Safe\DateTimeImmutable;
use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator;
use Symfony\Bridge\Doctrine\Types\UuidType;
use Symfony\Component\Uid\Uuid;
#[ORM\Entity(repositoryClass: GivenAnswerRepository::class)]
#[ORM\HasLifecycleCallbacks]
class GivenAnswer
{
#[ORM\Id]
#[ORM\Column(type: UuidType::NAME, unique: true)]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\CustomIdGenerator(class: UuidGenerator::class)]
private ?Uuid $id = null;
#[ORM\ManyToOne(inversedBy: 'givenAnswers')]
#[ORM\JoinColumn(nullable: false)]
private Candidate $candidate;
#[ORM\ManyToOne]
#[ORM\JoinColumn(nullable: false)]
private Quiz $quiz;
#[ORM\ManyToOne(inversedBy: 'givenAnswers')]
#[ORM\JoinColumn(nullable: true)]
private ?Answer $answer = null;
#[ORM\Column(type: Types::DATETIME_MUTABLE, nullable: false)]
private \DateTimeInterface $created;
public function getId(): ?Uuid
{
return $this->id;
}
public function getCandidate(): Candidate
{
return $this->candidate;
}
public function setCandidate(Candidate $candidate): static
{
$this->candidate = $candidate;
return $this;
}
public function getQuiz(): ?Quiz
{
return $this->quiz;
}
public function setQuiz(Quiz $quiz): static
{
$this->quiz = $quiz;
return $this;
}
public function getAnswer(): ?Answer
{
return $this->answer;
}
public function setAnswer(?Answer $answer): static
{
$this->answer = $answer;
return $this;
}
public function getCreated(): ?\DateTimeInterface
{
return $this->created;
}
#[ORM\PrePersist]
public function setCreatedAtValue(): void
{
$this->created = new DateTimeImmutable();
}
}

99
src/Entity/Question.php Normal file
View File

@@ -0,0 +1,99 @@
<?php
declare(strict_types=1);
namespace App\Entity;
use App\Repository\QuestionRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator;
use Symfony\Bridge\Doctrine\Types\UuidType;
use Symfony\Component\Uid\Uuid;
#[ORM\Entity(repositoryClass: QuestionRepository::class)]
class Question
{
#[ORM\Id]
#[ORM\Column(type: UuidType::NAME)]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\CustomIdGenerator(class: UuidGenerator::class)]
private ?Uuid $id = null;
#[ORM\Column(length: 255, nullable: false)]
private string $question;
#[ORM\ManyToOne(inversedBy: 'questions')]
#[ORM\JoinColumn(nullable: false)]
private Quiz $quiz;
#[ORM\Column]
private bool $enabled = true;
/** @var Collection<int, Answer> */
#[ORM\OneToMany(targetEntity: Answer::class, mappedBy: 'question', cascade: ['persist'], orphanRemoval: true)]
private Collection $answers;
public function __construct()
{
$this->answers = new ArrayCollection();
}
public function getId(): ?Uuid
{
return $this->id;
}
public function getQuestion(): string
{
return $this->question;
}
public function setQuestion(string $question): static
{
$this->question = $question;
return $this;
}
public function getQuiz(): Quiz
{
return $this->quiz;
}
public function setQuiz(Quiz $quiz): static
{
$this->quiz = $quiz;
return $this;
}
public function isEnabled(): ?bool
{
return $this->enabled;
}
public function setEnabled(bool $enabled): static
{
$this->enabled = $enabled;
return $this;
}
/** @return Collection<int, Answer> */
public function getAnswers(): Collection
{
return $this->answers;
}
public function addAnswer(Answer $answer): static
{
if (!$this->answers->contains($answer)) {
$this->answers->add($answer);
$answer->setQuestion($this);
}
return $this;
}
}

105
src/Entity/Quiz.php Normal file
View File

@@ -0,0 +1,105 @@
<?php
declare(strict_types=1);
namespace App\Entity;
use App\Repository\QuizRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator;
use Symfony\Bridge\Doctrine\Types\UuidType;
use Symfony\Component\Uid\Uuid;
#[ORM\Entity(repositoryClass: QuizRepository::class)]
class Quiz
{
#[ORM\Id]
#[ORM\Column(type: UuidType::NAME)]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\CustomIdGenerator(class: UuidGenerator::class)]
private ?Uuid $id = null;
#[ORM\Column(length: 64)]
private string $name;
#[ORM\ManyToOne(inversedBy: 'quizzes')]
#[ORM\JoinColumn(nullable: false)]
private Season $season;
/** @var Collection<int, Question> */
#[ORM\OneToMany(targetEntity: Question::class, mappedBy: 'quiz', cascade: ['persist'], orphanRemoval: true)]
private Collection $questions;
/** @var Collection<int, Correction> */
#[ORM\OneToMany(targetEntity: Correction::class, mappedBy: 'quiz', orphanRemoval: true)]
private Collection $corrections;
public function __construct()
{
$this->questions = new ArrayCollection();
$this->corrections = new ArrayCollection();
}
public function getId(): ?Uuid
{
return $this->id;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): static
{
$this->name = $name;
return $this;
}
public function getSeason(): Season
{
return $this->season;
}
public function setSeason(Season $season): static
{
$this->season = $season;
return $this;
}
/** @return Collection<int, Question> */
public function getQuestions(): Collection
{
return $this->questions;
}
public function addQuestion(Question $question): static
{
if (!$this->questions->contains($question)) {
$this->questions->add($question);
$question->setQuiz($this);
}
return $this;
}
/** @return Collection<int, Correction> */
public function getCorrections(): Collection
{
return $this->corrections;
}
public function addCorrection(Correction $correction): static
{
if (!$this->corrections->contains($correction)) {
$this->corrections->add($correction);
$correction->setQuiz($this);
}
return $this;
}
}

161
src/Entity/Season.php Normal file
View File

@@ -0,0 +1,161 @@
<?php
declare(strict_types=1);
namespace App\Entity;
use App\Repository\SeasonRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator;
use Symfony\Bridge\Doctrine\Types\UuidType;
use Symfony\Component\Uid\Uuid;
#[ORM\Entity(repositoryClass: SeasonRepository::class)]
class Season
{
#[ORM\Id]
#[ORM\Column(type: UuidType::NAME)]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\CustomIdGenerator(class: UuidGenerator::class)]
private ?Uuid $id = null;
#[ORM\Column(length: 64)]
private string $name;
#[ORM\Column(length: 5)]
private string $seasonCode;
#[ORM\Column]
private bool $preregisterCandidates;
/** @var Collection<int, Quiz> */
#[ORM\OneToMany(targetEntity: Quiz::class, mappedBy: 'season', orphanRemoval: true)]
private Collection $quizzes;
/** @var Collection<int, Candidate> */
#[ORM\OneToMany(targetEntity: Candidate::class, mappedBy: 'season', cascade: ['persist'], orphanRemoval: true)]
private Collection $candidates;
/** @var Collection<int, User> */
#[ORM\ManyToMany(targetEntity: User::class, inversedBy: 'seasons')]
private Collection $owners;
#[ORM\ManyToOne]
private ?Quiz $ActiveQuiz = null;
public function __construct()
{
$this->quizzes = new ArrayCollection();
$this->candidates = new ArrayCollection();
$this->owners = new ArrayCollection();
}
public function getId(): ?Uuid
{
return $this->id;
}
public function getName(): string
{
return $this->name;
}
public function setName(string $name): static
{
$this->name = $name;
return $this;
}
public function getSeasonCode(): ?string
{
return $this->seasonCode;
}
public function setSeasonCode(string $seasonCode): static
{
$this->seasonCode = $seasonCode;
return $this;
}
public function isPreregisterCandidates(): bool
{
return $this->preregisterCandidates;
}
public function setPreregisterCandidates(bool $preregisterCandidates): static
{
$this->preregisterCandidates = $preregisterCandidates;
return $this;
}
/** @return Collection<int, Quiz> */
public function getQuizzes(): Collection
{
return $this->quizzes;
}
public function addQuiz(Quiz $quiz): static
{
if (!$this->quizzes->contains($quiz)) {
$this->quizzes->add($quiz);
$quiz->setSeason($this);
}
return $this;
}
/** @return Collection<int, Candidate> */
public function getCandidates(): Collection
{
return $this->candidates;
}
public function addCandidate(Candidate $candidate): static
{
if (!$this->candidates->contains($candidate)) {
$this->candidates->add($candidate);
$candidate->setSeason($this);
}
return $this;
}
/** @return Collection<int, User> */
public function getOwners(): Collection
{
return $this->owners;
}
public function addOwner(User $owner): static
{
if (!$this->owners->contains($owner)) {
$this->owners->add($owner);
}
return $this;
}
public function removeOwner(User $owner): static
{
$this->owners->removeElement($owner);
return $this;
}
public function getActiveQuiz(): ?Quiz
{
return $this->ActiveQuiz;
}
public function setActiveQuiz(?Quiz $ActiveQuiz): static
{
$this->ActiveQuiz = $ActiveQuiz;
return $this;
}
}

143
src/Entity/User.php Normal file
View File

@@ -0,0 +1,143 @@
<?php
declare(strict_types=1);
namespace App\Entity;
use App\Repository\UserRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator;
use Symfony\Bridge\Doctrine\Types\UuidType;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Uid\Uuid;
#[ORM\Entity(repositoryClass: UserRepository::class)]
#[ORM\Table(name: '`user`')]
#[ORM\UniqueConstraint(name: 'UNIQ_IDENTIFIER_EMAIL', fields: ['email'])]
class User implements UserInterface, PasswordAuthenticatedUserInterface
{
#[ORM\Id]
#[ORM\Column(type: UuidType::NAME, unique: true)]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\CustomIdGenerator(class: UuidGenerator::class)]
private ?Uuid $id = null;
#[ORM\Column(length: 180)]
private string $email;
/** @var list<string> The user roles */
#[ORM\Column]
private array $roles = [];
/** @var string The hashed password */
#[ORM\Column]
private string $password;
/** @var Collection<int, Season> */
#[ORM\ManyToMany(targetEntity: Season::class, mappedBy: 'owners')]
private Collection $seasons;
public function __construct()
{
$this->seasons = new ArrayCollection();
}
public function getId(): ?Uuid
{
return $this->id;
}
public function getEmail(): ?string
{
return $this->email;
}
public function setEmail(string $email): static
{
$this->email = $email;
return $this;
}
/**
* A visual identifier that represents this user.
*
* @see UserInterface
*
* @return non-empty-string
*/
public function getUserIdentifier(): string
{
return $this->email;
}
/**
* @see UserInterface
*
* @return non-empty-list<string>
*/
public function getRoles(): array
{
$roles = $this->roles;
// guarantee every user at least has ROLE_USER
$roles[] = 'ROLE_USER';
return array_unique($roles);
}
/** @param list<string> $roles */
public function setRoles(array $roles): static
{
$this->roles = $roles;
return $this;
}
/** @see PasswordAuthenticatedUserInterface */
public function getPassword(): ?string
{
return $this->password;
}
public function setPassword(string $password): static
{
$this->password = $password;
return $this;
}
/** @see UserInterface */
public function eraseCredentials(): void
{
// If you store any temporary, sensitive data on the user, clear it here
// $this->plainPassword = null;
}
/** @return Collection<int, Season> */
public function getSeasons(): Collection
{
return $this->seasons;
}
public function addSeason(Season $season): static
{
if (!$this->seasons->contains($season)) {
$this->seasons->add($season);
$season->addOwner($this);
}
return $this;
}
public function removeSeason(Season $season): static
{
if ($this->seasons->removeElement($season)) {
$season->removeOwner($this);
}
return $this;
}
}