mirror of
https://github.com/MarijnDoeve/TijdVoorDeTest.git
synced 2026-03-05 20:44:19 +01:00
- Refactor ORM annotations across entities for consistency.
- Adjusted migrations to align with refactored ORM annotations. - Added new PHPStan and PHP-CS-Fixer configurations, including stricter rules. - Introduced `tests/object-manager.php` to improve test environment setup.
This commit is contained in:
@@ -5,13 +5,13 @@ use PhpCsFixer\Config;
|
||||
use PhpCsFixer\Finder;
|
||||
use PhpCsFixer\Runner\Parallel\ParallelConfigFactory;
|
||||
|
||||
$finder = (new Finder())
|
||||
$finder = new Finder()
|
||||
->in(__DIR__)
|
||||
->exclude('var')
|
||||
->exclude('bin')
|
||||
;
|
||||
|
||||
return (new Config())
|
||||
return new Config()
|
||||
->setParallelConfig(ParallelConfigFactory::detect())
|
||||
->setRules([
|
||||
'@Symfony' => true,
|
||||
@@ -30,8 +30,9 @@ return (new Config())
|
||||
'single_line_empty_body' => true,
|
||||
'strict_comparison' => true,
|
||||
'strict_param' => true,
|
||||
'ordered_attributes' => true,
|
||||
'heredoc_indentation' => ['indentation' => 'start_plus_one'],
|
||||
'trailing_comma_in_multiline' => ['after_heredoc' => true, 'elements' => ['arguments', 'array_destructuring', 'arrays', 'match', 'parameters']],
|
||||
|
||||
])
|
||||
->setRiskyAllowed(true)
|
||||
->setFinder($finder)
|
||||
|
||||
@@ -15,7 +15,6 @@ services:
|
||||
# See https://xdebug.org/docs/all_settings#mode
|
||||
XDEBUG_MODE: "${XDEBUG_MODE:-off}"
|
||||
MAILER_DSN: "smtp://mailer:1025"
|
||||
PHP_CS_FIXER_IGNORE_ENV: 1
|
||||
extra_hosts:
|
||||
# Ensure that host.docker.internal is correctly defined on Linux
|
||||
- host.docker.internal:host-gateway
|
||||
|
||||
@@ -8,3 +8,7 @@ parameters:
|
||||
- src/
|
||||
- tests/
|
||||
treatPhpDocTypesAsCertain: false
|
||||
symfony:
|
||||
containerXmlPath: var/cache/dev/Tvdt_KernelDevDebugContainer.xml
|
||||
doctrine:
|
||||
objectManagerLoader: tests/object-manager.php
|
||||
|
||||
@@ -33,12 +33,12 @@ class QuizController extends AbstractController
|
||||
private readonly TranslatorInterface $translator,
|
||||
) {}
|
||||
|
||||
#[IsGranted(SeasonVoter::EDIT, subject: 'season')]
|
||||
#[Route(
|
||||
'/backoffice/season/{seasonCode:season}/quiz/{quiz}',
|
||||
name: 'tvdt_backoffice_quiz',
|
||||
requirements: ['seasonCode' => self::SEASON_CODE_REGEX, 'quiz' => Requirement::UUID],
|
||||
)]
|
||||
#[IsGranted(SeasonVoter::EDIT, subject: 'season')]
|
||||
public function index(Season $season, Quiz $quiz): Response
|
||||
{
|
||||
return $this->render('backoffice/quiz.html.twig', [
|
||||
@@ -48,12 +48,12 @@ class QuizController extends AbstractController
|
||||
]);
|
||||
}
|
||||
|
||||
#[IsGranted(SeasonVoter::EDIT, subject: 'season')]
|
||||
#[Route(
|
||||
'/backoffice/season/{seasonCode:season}/quiz/{quiz}/enable',
|
||||
name: 'tvdt_backoffice_enable',
|
||||
requirements: ['seasonCode' => self::SEASON_CODE_REGEX, 'quiz' => Requirement::UUID.'|null'],
|
||||
)]
|
||||
#[IsGranted(SeasonVoter::EDIT, subject: 'season')]
|
||||
public function enableQuiz(Season $season, ?Quiz $quiz, EntityManagerInterface $em): RedirectResponse
|
||||
{
|
||||
$season->setActiveQuiz($quiz);
|
||||
@@ -66,12 +66,12 @@ class QuizController extends AbstractController
|
||||
return $this->redirectToRoute('tvdt_backoffice_season', ['seasonCode' => $season->getSeasonCode()]);
|
||||
}
|
||||
|
||||
#[IsGranted(SeasonVoter::EDIT, subject: 'quiz')]
|
||||
#[Route(
|
||||
'/backoffice/quiz/{quiz}/clear',
|
||||
name: 'tvdt_backoffice_quiz_clear',
|
||||
requirements: ['quiz' => Requirement::UUID],
|
||||
)]
|
||||
#[IsGranted(SeasonVoter::EDIT, subject: 'quiz')]
|
||||
public function clearQuiz(Quiz $quiz, QuizRepository $quizRepository): RedirectResponse
|
||||
{
|
||||
try {
|
||||
@@ -84,12 +84,12 @@ class QuizController extends AbstractController
|
||||
return $this->redirectToRoute('tvdt_backoffice_quiz', ['seasonCode' => $quiz->getSeason()->getSeasonCode(), 'quiz' => $quiz->getId()]);
|
||||
}
|
||||
|
||||
#[IsGranted(SeasonVoter::DELETE, subject: 'quiz')]
|
||||
#[Route(
|
||||
'/backoffice/quiz/{quiz}/delete',
|
||||
name: 'tvdt_backoffice_quiz_delete',
|
||||
requirements: ['quiz' => Requirement::UUID],
|
||||
)]
|
||||
#[IsGranted(SeasonVoter::DELETE, subject: 'quiz')]
|
||||
public function deleteQuiz(Quiz $quiz, QuizRepository $quizRepository): RedirectResponse
|
||||
{
|
||||
$quizRepository->deleteQuiz($quiz);
|
||||
@@ -99,12 +99,12 @@ class QuizController extends AbstractController
|
||||
return $this->redirectToRoute('tvdt_backoffice_season', ['seasonCode' => $quiz->getSeason()->getSeasonCode()]);
|
||||
}
|
||||
|
||||
#[IsGranted(SeasonVoter::EDIT, subject: 'quiz')]
|
||||
#[Route(
|
||||
'/backoffice/quiz/{quiz}/candidate/{candidate}/modify_correction',
|
||||
name: 'tvdt_backoffice_modify_correction',
|
||||
requirements: ['quiz' => Requirement::UUID, 'candidate' => Requirement::UUID],
|
||||
)]
|
||||
#[IsGranted(SeasonVoter::EDIT, subject: 'quiz')]
|
||||
public function modifyCorrection(Quiz $quiz, Candidate $candidate, QuizCandidateRepository $quizCandidateRepository, Request $request): RedirectResponse
|
||||
{
|
||||
if (!$request->isMethod('POST')) {
|
||||
|
||||
@@ -32,12 +32,12 @@ class SeasonController extends AbstractController
|
||||
private readonly EntityManagerInterface $em,
|
||||
) {}
|
||||
|
||||
#[IsGranted(SeasonVoter::EDIT, subject: 'season')]
|
||||
#[Route(
|
||||
'/backoffice/season/{seasonCode:season}',
|
||||
name: 'tvdt_backoffice_season',
|
||||
requirements: ['seasonCode' => self::SEASON_CODE_REGEX],
|
||||
)]
|
||||
#[IsGranted(SeasonVoter::EDIT, subject: 'season')]
|
||||
public function index(Season $season, Request $request): Response
|
||||
{
|
||||
$form = $this->createForm(SettingsForm::class, $season->getSettings());
|
||||
@@ -54,13 +54,13 @@ class SeasonController extends AbstractController
|
||||
]);
|
||||
}
|
||||
|
||||
#[IsGranted(SeasonVoter::EDIT, subject: 'season')]
|
||||
#[Route(
|
||||
'/backoffice/season/{seasonCode:season}/add-candidate',
|
||||
name: 'tvdt_backoffice_add_candidates',
|
||||
requirements: ['seasonCode' => self::SEASON_CODE_REGEX],
|
||||
priority: 10,
|
||||
)]
|
||||
#[IsGranted(SeasonVoter::EDIT, subject: 'season')]
|
||||
public function addCandidates(Season $season, Request $request): Response
|
||||
{
|
||||
$form = $this->createForm(AddCandidatesFormType::class);
|
||||
@@ -80,13 +80,13 @@ class SeasonController extends AbstractController
|
||||
return $this->render('backoffice/season_add_candidates.html.twig', ['form' => $form]);
|
||||
}
|
||||
|
||||
#[IsGranted(SeasonVoter::EDIT, subject: 'season')]
|
||||
#[Route(
|
||||
'/backoffice/season/{seasonCode:season}/add-quiz',
|
||||
name: 'tvdt_backoffice_quiz_add',
|
||||
requirements: ['seasonCode' => self::SEASON_CODE_REGEX],
|
||||
priority: 10,
|
||||
)]
|
||||
#[IsGranted(SeasonVoter::EDIT, subject: 'season')]
|
||||
public function addQuiz(Request $request, Season $season, QuizSpreadsheetService $quizSpreadsheet): Response
|
||||
{
|
||||
$quiz = new Quiz();
|
||||
|
||||
@@ -28,8 +28,8 @@ final class EliminationController extends AbstractController
|
||||
{
|
||||
public function __construct(private readonly TranslatorInterface $translator) {}
|
||||
|
||||
#[Route('/elimination/{elimination}', name: 'tvdt_elimination', requirements: ['elimination' => Requirement::UUID])]
|
||||
#[IsGranted(SeasonVoter::ELIMINATION, 'elimination')]
|
||||
#[Route('/elimination/{elimination}', name: 'tvdt_elimination', requirements: ['elimination' => Requirement::UUID])]
|
||||
public function index(#[MapEntity] Elimination $elimination, Request $request): Response
|
||||
{
|
||||
$form = $this->createForm(EliminationEnterNameType::class);
|
||||
@@ -48,8 +48,8 @@ final class EliminationController extends AbstractController
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/elimination/{elimination}/{candidateHash}', name: 'tvdt_elimination_candidate', requirements: ['elimination' => Requirement::UUID, 'candidateHash' => self::CANDIDATE_HASH_REGEX])]
|
||||
#[IsGranted(SeasonVoter::ELIMINATION, 'elimination')]
|
||||
#[Route('/elimination/{elimination}/{candidateHash}', name: 'tvdt_elimination_candidate', requirements: ['elimination' => Requirement::UUID, 'candidateHash' => self::CANDIDATE_HASH_REGEX])]
|
||||
public function candidateScreen(Elimination $elimination, string $candidateHash, CandidateRepository $candidateRepository): Response
|
||||
{
|
||||
$candidate = $candidateRepository->getCandidateByHash($elimination->getQuiz()->getSeason(), $candidateHash);
|
||||
|
||||
@@ -16,17 +16,17 @@ use Tvdt\Repository\AnswerRepository;
|
||||
#[ORM\Entity(repositoryClass: AnswerRepository::class)]
|
||||
class Answer
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\Column(type: UuidType::NAME)]
|
||||
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
|
||||
#[ORM\CustomIdGenerator(class: UuidGenerator::class)]
|
||||
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
|
||||
#[ORM\Id]
|
||||
private Uuid $id;
|
||||
|
||||
#[ORM\Column(type: Types::SMALLINT, options: ['default' => 0])]
|
||||
private int $ordering = 0;
|
||||
|
||||
#[ORM\ManyToOne(inversedBy: 'answers')]
|
||||
#[ORM\JoinColumn(nullable: false)]
|
||||
#[ORM\ManyToOne(inversedBy: 'answers')]
|
||||
private Question $question;
|
||||
|
||||
/** @var Collection<int, Candidate> */
|
||||
|
||||
@@ -17,14 +17,14 @@ use Tvdt\Repository\CandidateRepository;
|
||||
#[ORM\UniqueConstraint(fields: ['name', 'season'])]
|
||||
class Candidate
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\Column(type: UuidType::NAME, unique: true)]
|
||||
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
|
||||
#[ORM\CustomIdGenerator(class: UuidGenerator::class)]
|
||||
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
|
||||
#[ORM\Id]
|
||||
private Uuid $id;
|
||||
|
||||
#[ORM\ManyToOne(inversedBy: 'candidates')]
|
||||
#[ORM\JoinColumn(nullable: false)]
|
||||
#[ORM\ManyToOne(inversedBy: 'candidates')]
|
||||
private Season $season;
|
||||
|
||||
/** @var Collection<int, Answer> */
|
||||
|
||||
@@ -21,10 +21,10 @@ class Elimination
|
||||
|
||||
public const string SCREEN_RED = 'red';
|
||||
|
||||
#[ORM\Id]
|
||||
#[ORM\Column(type: UuidType::NAME, unique: true)]
|
||||
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
|
||||
#[ORM\CustomIdGenerator(class: UuidGenerator::class)]
|
||||
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
|
||||
#[ORM\Id]
|
||||
private Uuid $id;
|
||||
|
||||
/** @var array<string, mixed> */
|
||||
@@ -35,8 +35,8 @@ class Elimination
|
||||
private \DateTimeImmutable $created;
|
||||
|
||||
public function __construct(
|
||||
#[ORM\ManyToOne(inversedBy: 'eliminations')]
|
||||
#[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')]
|
||||
#[ORM\ManyToOne(inversedBy: 'eliminations')]
|
||||
private Quiz $quiz,
|
||||
) {}
|
||||
|
||||
|
||||
@@ -16,26 +16,26 @@ use Tvdt\Repository\GivenAnswerRepository;
|
||||
#[ORM\HasLifecycleCallbacks]
|
||||
class GivenAnswer
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\Column(type: UuidType::NAME, unique: true)]
|
||||
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
|
||||
#[ORM\CustomIdGenerator(class: UuidGenerator::class)]
|
||||
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
|
||||
#[ORM\Id]
|
||||
private Uuid $id;
|
||||
|
||||
#[ORM\Column(type: Types::DATETIMETZ_IMMUTABLE, nullable: false)]
|
||||
private \DateTimeImmutable $created;
|
||||
|
||||
public function __construct(
|
||||
#[ORM\ManyToOne(inversedBy: 'givenAnswers')]
|
||||
#[ORM\JoinColumn(nullable: false)]
|
||||
#[ORM\ManyToOne(inversedBy: 'givenAnswers')]
|
||||
private Candidate $candidate,
|
||||
|
||||
#[ORM\ManyToOne]
|
||||
#[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')]
|
||||
#[ORM\ManyToOne]
|
||||
private Quiz $quiz,
|
||||
|
||||
#[ORM\ManyToOne(inversedBy: 'givenAnswers')]
|
||||
#[ORM\JoinColumn(nullable: false)]
|
||||
#[ORM\ManyToOne(inversedBy: 'givenAnswers')]
|
||||
private Answer $answer,
|
||||
) {}
|
||||
|
||||
|
||||
@@ -16,10 +16,10 @@ use Tvdt\Repository\QuestionRepository;
|
||||
#[ORM\Entity(repositoryClass: QuestionRepository::class)]
|
||||
class Question
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\Column(type: UuidType::NAME)]
|
||||
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
|
||||
#[ORM\CustomIdGenerator(class: UuidGenerator::class)]
|
||||
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
|
||||
#[ORM\Id]
|
||||
private Uuid $id;
|
||||
|
||||
#[ORM\Column(type: Types::SMALLINT, options: ['default' => 0])]
|
||||
@@ -28,8 +28,8 @@ class Question
|
||||
#[ORM\Column(type: Types::STRING, length: 255)]
|
||||
private string $question;
|
||||
|
||||
#[ORM\ManyToOne(inversedBy: 'questions')]
|
||||
#[ORM\JoinColumn(nullable: false)]
|
||||
#[ORM\ManyToOne(inversedBy: 'questions')]
|
||||
private Quiz $quiz;
|
||||
|
||||
#[ORM\Column]
|
||||
|
||||
@@ -16,17 +16,17 @@ use Tvdt\Repository\QuizRepository;
|
||||
#[ORM\UniqueConstraint(fields: ['name', 'season'])]
|
||||
class Quiz
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\Column(type: UuidType::NAME)]
|
||||
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
|
||||
#[ORM\CustomIdGenerator(class: UuidGenerator::class)]
|
||||
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
|
||||
#[ORM\Id]
|
||||
private Uuid $id;
|
||||
|
||||
#[ORM\Column(length: 64)]
|
||||
private string $name;
|
||||
|
||||
#[ORM\ManyToOne(inversedBy: 'quizzes')]
|
||||
#[ORM\JoinColumn(nullable: false)]
|
||||
#[ORM\ManyToOne(inversedBy: 'quizzes')]
|
||||
private Season $season;
|
||||
|
||||
/** @var Collection<int, Question> */
|
||||
|
||||
@@ -13,14 +13,14 @@ use Symfony\Component\Uid\Uuid;
|
||||
use Tvdt\Repository\QuizCandidateRepository;
|
||||
|
||||
#[ORM\Entity(repositoryClass: QuizCandidateRepository::class)]
|
||||
#[ORM\UniqueConstraint(columns: ['candidate_id', 'quiz_id'])]
|
||||
#[ORM\HasLifecycleCallbacks]
|
||||
#[ORM\UniqueConstraint(columns: ['candidate_id', 'quiz_id'])]
|
||||
class QuizCandidate
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\Column(type: UuidType::NAME, unique: true)]
|
||||
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
|
||||
#[ORM\CustomIdGenerator(class: UuidGenerator::class)]
|
||||
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
|
||||
#[ORM\Id]
|
||||
private Uuid $id;
|
||||
|
||||
#[ORM\Column]
|
||||
@@ -30,12 +30,12 @@ class QuizCandidate
|
||||
private \DateTimeImmutable $created;
|
||||
|
||||
public function __construct(
|
||||
#[ORM\ManyToOne(inversedBy: 'candidateData')]
|
||||
#[ORM\JoinColumn(nullable: false)]
|
||||
#[ORM\ManyToOne(inversedBy: 'candidateData')]
|
||||
private Quiz $quiz,
|
||||
|
||||
#[ORM\ManyToOne(inversedBy: 'quizData')]
|
||||
#[ORM\JoinColumn(nullable: false)]
|
||||
#[ORM\ManyToOne(inversedBy: 'quizData')]
|
||||
private Candidate $candidate,
|
||||
) {}
|
||||
|
||||
|
||||
@@ -17,10 +17,10 @@ class Season
|
||||
{
|
||||
private const string SEASON_CODE_CHARACTERS = 'bcdfghjklmnpqrstvwxz';
|
||||
|
||||
#[ORM\Id]
|
||||
#[ORM\Column(type: UuidType::NAME)]
|
||||
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
|
||||
#[ORM\CustomIdGenerator(class: UuidGenerator::class)]
|
||||
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
|
||||
#[ORM\Id]
|
||||
private Uuid $id;
|
||||
|
||||
#[ORM\Column(length: 64)]
|
||||
@@ -42,12 +42,12 @@ class Season
|
||||
#[ORM\ManyToMany(targetEntity: User::class, inversedBy: 'seasons')]
|
||||
private Collection $owners;
|
||||
|
||||
#[ORM\ManyToOne]
|
||||
#[ORM\JoinColumn(nullable: true, onDelete: 'SET NULL')]
|
||||
#[ORM\ManyToOne]
|
||||
private ?Quiz $ActiveQuiz = null;
|
||||
|
||||
#[ORM\OneToOne(cascade: ['persist', 'remove'])]
|
||||
#[ORM\JoinColumn(nullable: true)]
|
||||
#[ORM\OneToOne(cascade: ['persist', 'remove'])]
|
||||
private ?SeasonSettings $settings = null;
|
||||
|
||||
public function __construct()
|
||||
|
||||
@@ -14,10 +14,10 @@ use Tvdt\Repository\SeasonSettingsRepository;
|
||||
#[ORM\Entity(repositoryClass: SeasonSettingsRepository::class)]
|
||||
class SeasonSettings
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
|
||||
#[ORM\Column(type: UuidType::NAME)]
|
||||
#[ORM\CustomIdGenerator(class: UuidGenerator::class)]
|
||||
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
|
||||
#[ORM\Id]
|
||||
private Uuid $id;
|
||||
|
||||
#[ORM\Column(type: Types::BOOLEAN, options: ['default' => false])]
|
||||
|
||||
@@ -22,10 +22,10 @@ use Tvdt\Repository\UserRepository;
|
||||
#[UniqueEntity(fields: ['email'], message: 'There is already an account with this email')]
|
||||
class User implements UserInterface, PasswordAuthenticatedUserInterface
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\Column(type: UuidType::NAME, unique: true)]
|
||||
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
|
||||
#[ORM\CustomIdGenerator(class: UuidGenerator::class)]
|
||||
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
|
||||
#[ORM\Id]
|
||||
private Uuid $id;
|
||||
|
||||
#[ORM\Column(length: 180)]
|
||||
|
||||
@@ -60,10 +60,10 @@ class CandidateRepository extends ServiceEntityRepository
|
||||
select
|
||||
c.id,
|
||||
c.name,
|
||||
sum(case when a.isRightAnswer = true then 1 else 0 end) as correct,
|
||||
count(case when a.isRightAnswer = true then 1 else null end) as correct,
|
||||
qc.corrections,
|
||||
max(ga.created) - qc.created as time,
|
||||
(sum(case when a.isRightAnswer = true then 1 else 0 end) + qc.corrections) as score
|
||||
(count(case when a.isRightAnswer = true then 1 else null end) + qc.corrections) as score
|
||||
from Tvdt\Entity\Candidate c
|
||||
join c.givenAnswers ga
|
||||
join ga.answer a
|
||||
|
||||
15
tests/object-manager.php
Normal file
15
tests/object-manager.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Symfony\Component\Dotenv\Dotenv;
|
||||
use Tvdt\Kernel;
|
||||
|
||||
require __DIR__.'/../vendor/autoload.php';
|
||||
|
||||
new Dotenv()->bootEnv(__DIR__.'/../.env');
|
||||
|
||||
$kernel = new Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']);
|
||||
$kernel->boot();
|
||||
|
||||
return $kernel->getContainer()->get('doctrine')->getManager();
|
||||
Reference in New Issue
Block a user