From 0ccce51af841bae77cc7fad1fd72cfeecd8867dd Mon Sep 17 00:00:00 2001 From: Marijn Doeve Date: Wed, 5 Mar 2025 21:01:57 +0100 Subject: [PATCH] Add AbstractController, implement flash message handling, and refactor repositories --- config/bundles.php | 2 + src/Controller/AbstractController.php | 19 ++++++++ src/Controller/Admin/AnswerCrudController.php | 2 + .../Admin/CandidateCrudController.php | 2 + .../Admin/CorrectionCrudController.php | 2 + .../Admin/GivenAnswerCrudController.php | 2 + .../Admin/QuestionCrudController.php | 2 + src/Controller/Admin/QuizCrudController.php | 2 + src/Controller/Admin/SeasonCrudController.php | 2 + src/Controller/Admin/UserCrudController.php | 2 + src/Controller/QuizController.php | 43 +++++++++++++++++-- src/Enum/FlashType.php | 2 +- src/Form/EnterNameType.php | 9 ---- src/Helpers/Base64.php | 2 +- src/Repository/CandidateRepository.php | 9 ++++ src/Repository/GivenAnswerRepository.php | 9 ++++ src/Repository/QuestionRepository.php | 6 +-- templates/quiz/question.twig | 15 +++++-- 18 files changed, 111 insertions(+), 21 deletions(-) create mode 100644 src/Controller/AbstractController.php diff --git a/config/bundles.php b/config/bundles.php index a60a43e..8de0245 100644 --- a/config/bundles.php +++ b/config/bundles.php @@ -1,5 +1,7 @@ ['all' => true], Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true], diff --git a/src/Controller/AbstractController.php b/src/Controller/AbstractController.php new file mode 100644 index 0000000..1853af9 --- /dev/null +++ b/src/Controller/AbstractController.php @@ -0,0 +1,19 @@ +value; + } + parent::addFlash($type, $message); + } +} diff --git a/src/Controller/Admin/AnswerCrudController.php b/src/Controller/Admin/AnswerCrudController.php index f50a78b..a98184f 100644 --- a/src/Controller/Admin/AnswerCrudController.php +++ b/src/Controller/Admin/AnswerCrudController.php @@ -1,5 +1,7 @@ self::SEASON_CODE_REGEX])] public function enterName( Request $request, + #[MapEntity(mapping: ['seasonCode' => 'seasonCode'])] Season $season, ): Response { $form = $this->createForm(EnterNameType::class); @@ -64,22 +71,50 @@ class QuizController extends AbstractController requirements: ['seasonCode' => self::SEASON_CODE_REGEX, 'nameHash' => self::CANDIDATE_HASH_REGEX], )] public function quizPage( + #[MapEntity(mapping: ['seasonCode' => 'seasonCode'])] Season $season, string $nameHash, CandidateRepository $candidateRepository, QuestionRepository $questionRepository, + AnswerRepository $answerRepository, + GivenAnswerRepository $givenAnswerRepository, + Request $request, ): Response { $candidate = $candidateRepository->getCandidateByHash($season, $nameHash); if (!$candidate instanceof Candidate) { - // Add option to add new candidate when preregister is disabled - $this->addFlash(FlashType::Danger->value, 'Candidate not found'); + if (false === $season->isPreregisterCandidates()) { + $candidate = new Candidate(Base64::base64_url_decode($nameHash)); + $candidateRepository->save($candidate); + } else { + $this->addFlash(FlashType::Danger, 'Candidate not found'); - return $this->redirectToRoute('enter_name', ['seasonCode' => $season->getSeasonCode()]); + return $this->redirectToRoute('enter_name', ['seasonCode' => $season->getSeasonCode()]); + } + } + + if ('POST' === $request->getMethod()) { + $answer = $answerRepository->findOneBy(['id' => $request->request->get('answer')]); + + if (!$answer instanceof Answer) { + throw new BadRequestException('Invalid Answer ID'); + } + + $givenAnswer = new GivenAnswer(); + $givenAnswer->setCandidate($candidate) + ->setAnswer($answer) + ->setQuiz($answer->getQuestion()->getQuiz()); + $givenAnswerRepository->save($givenAnswer); } $question = $questionRepository->findNextQuestionForCandidate($candidate); + if (!$question instanceof Question) { + $this->addFlash(FlashType::Success, 'Quiz completed'); + + return $this->redirectToRoute('enter_name', ['seasonCode' => $season->getSeasonCode()]); + } + return $this->render('quiz/question.twig', ['candidate' => $candidate, 'question' => $question]); } } diff --git a/src/Enum/FlashType.php b/src/Enum/FlashType.php index e13d2e7..6ed9ae8 100644 --- a/src/Enum/FlashType.php +++ b/src/Enum/FlashType.php @@ -12,6 +12,6 @@ enum FlashType: string case Danger = 'danger'; case Warning = 'warning'; case Info = 'info'; - case Ligt = 'light'; + case Light = 'light'; case Dark = 'dark'; } diff --git a/src/Form/EnterNameType.php b/src/Form/EnterNameType.php index e5bdcd8..b130296 100644 --- a/src/Form/EnterNameType.php +++ b/src/Form/EnterNameType.php @@ -7,7 +7,6 @@ namespace App\Form; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; -use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Contracts\Translation\TranslatorInterface; class EnterNameType extends AbstractType @@ -22,14 +21,6 @@ class EnterNameType extends AbstractType ->add('name', TextType::class, ['required' => true, 'label' => $this->translator->trans('Enter your name')], ) -// ->add('submit', SubmitType::class, ['label' => 'Start quiz']) ; } - - public function configureOptions(OptionsResolver $resolver): void - { - $resolver->setDefaults([ - // Configure your form options here - ]); - } } diff --git a/src/Helpers/Base64.php b/src/Helpers/Base64.php index c2e72ef..991c9e5 100644 --- a/src/Helpers/Base64.php +++ b/src/Helpers/Base64.php @@ -14,7 +14,7 @@ class Base64 public static function base64_url_encode(string $input): string { - return strtr(base64_encode($input), '+/', '-_'); + return rtrim(strtr(base64_encode($input), '+/', '-_'), '='); } /** @throws UrlException */ diff --git a/src/Repository/CandidateRepository.php b/src/Repository/CandidateRepository.php index 5658785..cda370c 100644 --- a/src/Repository/CandidateRepository.php +++ b/src/Repository/CandidateRepository.php @@ -36,4 +36,13 @@ class CandidateRepository extends ServiceEntityRepository ->setParameter('name', $name) ->getQuery()->getOneOrNullResult(); } + + public function save(Candidate $candidate, bool $flush = true): void + { + $this->getEntityManager()->persist($candidate); + + if (true === $flush) { + $this->getEntityManager()->flush(); + } + } } diff --git a/src/Repository/GivenAnswerRepository.php b/src/Repository/GivenAnswerRepository.php index 598f1ed..116b418 100644 --- a/src/Repository/GivenAnswerRepository.php +++ b/src/Repository/GivenAnswerRepository.php @@ -17,4 +17,13 @@ class GivenAnswerRepository extends ServiceEntityRepository { parent::__construct($registry, GivenAnswer::class); } + + public function save(GivenAnswer $givenAnswer, bool $flush = true): void + { + $this->getEntityManager()->persist($givenAnswer); + + if (true === $flush) { + $this->getEntityManager()->flush(); + } + } } diff --git a/src/Repository/QuestionRepository.php b/src/Repository/QuestionRepository.php index 37d6d7a..2bbb123 100644 --- a/src/Repository/QuestionRepository.php +++ b/src/Repository/QuestionRepository.php @@ -20,13 +20,13 @@ class QuestionRepository extends ServiceEntityRepository parent::__construct($registry, Question::class); } - public function findNextQuestionForCandidate(Candidate $candidate): Question + public function findNextQuestionForCandidate(Candidate $candidate): ?Question { $qb = $this->createQueryBuilder('q'); return $qb->join('q.quiz', 'qz') ->andWhere($qb->expr()->notIn('q.id', $this->getEntityManager()->createQueryBuilder() - ->select('ga.id') + ->select('q1') ->from(GivenAnswer::class, 'ga') ->join('ga.answer', 'a') ->join('a.question', 'q1') @@ -38,6 +38,6 @@ class QuestionRepository extends ServiceEntityRepository ->setMaxResults(1) ->setParameter('candidate', $candidate) ->setParameter('quiz', $candidate->getSeason()->getActiveQuiz()) - ->getQuery()->getSingleResult(); + ->getQuery()->getOneOrNullResult(); } } diff --git a/templates/quiz/question.twig b/templates/quiz/question.twig index bee4556..142f6a3 100644 --- a/templates/quiz/question.twig +++ b/templates/quiz/question.twig @@ -3,7 +3,16 @@ Candiadte: {{ candidate.name }}
{{ question.question }}
- {% for answer in question.answers %} - {{ answer.text }} - {% endfor %} +
+ {% for answer in question.answers %} +
+ +
+ {% else %} + Weirdly enough this question has no answers... + {% endfor %} +
{% endblock body %}