mirror of
https://github.com/MarijnDoeve/TijdVoorDeTest.git
synced 2026-03-05 20:44:19 +01:00
Add AbstractController, implement flash message handling, and refactor repositories
This commit is contained in:
@@ -1,5 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
|
Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
|
||||||
Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true],
|
Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true],
|
||||||
|
|||||||
19
src/Controller/AbstractController.php
Normal file
19
src/Controller/AbstractController.php
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Controller;
|
||||||
|
|
||||||
|
use App\Enum\FlashType;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController as AbstractBaseController;
|
||||||
|
|
||||||
|
abstract class AbstractController extends AbstractBaseController
|
||||||
|
{
|
||||||
|
protected function addFlash(FlashType|string $type, mixed $message): void
|
||||||
|
{
|
||||||
|
if ($type instanceof FlashType) {
|
||||||
|
$type = $type->value;
|
||||||
|
}
|
||||||
|
parent::addFlash($type, $message);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Controller\Admin;
|
namespace App\Controller\Admin;
|
||||||
|
|
||||||
use App\Entity\Answer;
|
use App\Entity\Answer;
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Controller\Admin;
|
namespace App\Controller\Admin;
|
||||||
|
|
||||||
use App\Entity\Candidate;
|
use App\Entity\Candidate;
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Controller\Admin;
|
namespace App\Controller\Admin;
|
||||||
|
|
||||||
use App\Entity\Correction;
|
use App\Entity\Correction;
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Controller\Admin;
|
namespace App\Controller\Admin;
|
||||||
|
|
||||||
use App\Entity\GivenAnswer;
|
use App\Entity\GivenAnswer;
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Controller\Admin;
|
namespace App\Controller\Admin;
|
||||||
|
|
||||||
use App\Entity\Question;
|
use App\Entity\Question;
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Controller\Admin;
|
namespace App\Controller\Admin;
|
||||||
|
|
||||||
use App\Entity\Quiz;
|
use App\Entity\Quiz;
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Controller\Admin;
|
namespace App\Controller\Admin;
|
||||||
|
|
||||||
use App\Entity\Season;
|
use App\Entity\Season;
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Controller\Admin;
|
namespace App\Controller\Admin;
|
||||||
|
|
||||||
use App\Entity\User;
|
use App\Entity\User;
|
||||||
|
|||||||
@@ -4,15 +4,21 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Controller;
|
namespace App\Controller;
|
||||||
|
|
||||||
|
use App\Entity\Answer;
|
||||||
use App\Entity\Candidate;
|
use App\Entity\Candidate;
|
||||||
|
use App\Entity\GivenAnswer;
|
||||||
|
use App\Entity\Question;
|
||||||
use App\Entity\Season;
|
use App\Entity\Season;
|
||||||
use App\Enum\FlashType;
|
use App\Enum\FlashType;
|
||||||
use App\Form\EnterNameType;
|
use App\Form\EnterNameType;
|
||||||
use App\Form\SelectSeasonType;
|
use App\Form\SelectSeasonType;
|
||||||
use App\Helpers\Base64;
|
use App\Helpers\Base64;
|
||||||
|
use App\Repository\AnswerRepository;
|
||||||
use App\Repository\CandidateRepository;
|
use App\Repository\CandidateRepository;
|
||||||
|
use App\Repository\GivenAnswerRepository;
|
||||||
use App\Repository\QuestionRepository;
|
use App\Repository\QuestionRepository;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bridge\Doctrine\Attribute\MapEntity;
|
||||||
|
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\HttpKernel\Attribute\AsController;
|
use Symfony\Component\HttpKernel\Attribute\AsController;
|
||||||
@@ -42,6 +48,7 @@ class QuizController extends AbstractController
|
|||||||
#[Route(path: '/{seasonCode}', name: 'enter_name', requirements: ['seasonCode' => self::SEASON_CODE_REGEX])]
|
#[Route(path: '/{seasonCode}', name: 'enter_name', requirements: ['seasonCode' => self::SEASON_CODE_REGEX])]
|
||||||
public function enterName(
|
public function enterName(
|
||||||
Request $request,
|
Request $request,
|
||||||
|
#[MapEntity(mapping: ['seasonCode' => 'seasonCode'])]
|
||||||
Season $season,
|
Season $season,
|
||||||
): Response {
|
): Response {
|
||||||
$form = $this->createForm(EnterNameType::class);
|
$form = $this->createForm(EnterNameType::class);
|
||||||
@@ -64,22 +71,50 @@ class QuizController extends AbstractController
|
|||||||
requirements: ['seasonCode' => self::SEASON_CODE_REGEX, 'nameHash' => self::CANDIDATE_HASH_REGEX],
|
requirements: ['seasonCode' => self::SEASON_CODE_REGEX, 'nameHash' => self::CANDIDATE_HASH_REGEX],
|
||||||
)]
|
)]
|
||||||
public function quizPage(
|
public function quizPage(
|
||||||
|
#[MapEntity(mapping: ['seasonCode' => 'seasonCode'])]
|
||||||
Season $season,
|
Season $season,
|
||||||
string $nameHash,
|
string $nameHash,
|
||||||
CandidateRepository $candidateRepository,
|
CandidateRepository $candidateRepository,
|
||||||
QuestionRepository $questionRepository,
|
QuestionRepository $questionRepository,
|
||||||
|
AnswerRepository $answerRepository,
|
||||||
|
GivenAnswerRepository $givenAnswerRepository,
|
||||||
|
Request $request,
|
||||||
): Response {
|
): Response {
|
||||||
$candidate = $candidateRepository->getCandidateByHash($season, $nameHash);
|
$candidate = $candidateRepository->getCandidateByHash($season, $nameHash);
|
||||||
|
|
||||||
if (!$candidate instanceof Candidate) {
|
if (!$candidate instanceof Candidate) {
|
||||||
// Add option to add new candidate when preregister is disabled
|
if (false === $season->isPreregisterCandidates()) {
|
||||||
$this->addFlash(FlashType::Danger->value, 'Candidate not found');
|
$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);
|
$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]);
|
return $this->render('quiz/question.twig', ['candidate' => $candidate, 'question' => $question]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,6 @@ enum FlashType: string
|
|||||||
case Danger = 'danger';
|
case Danger = 'danger';
|
||||||
case Warning = 'warning';
|
case Warning = 'warning';
|
||||||
case Info = 'info';
|
case Info = 'info';
|
||||||
case Ligt = 'light';
|
case Light = 'light';
|
||||||
case Dark = 'dark';
|
case Dark = 'dark';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ namespace App\Form;
|
|||||||
use Symfony\Component\Form\AbstractType;
|
use Symfony\Component\Form\AbstractType;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
|
||||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
|
|
||||||
class EnterNameType extends AbstractType
|
class EnterNameType extends AbstractType
|
||||||
@@ -22,14 +21,6 @@ class EnterNameType extends AbstractType
|
|||||||
->add('name', TextType::class,
|
->add('name', TextType::class,
|
||||||
['required' => true, 'label' => $this->translator->trans('Enter your name')],
|
['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
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ class Base64
|
|||||||
|
|
||||||
public static function base64_url_encode(string $input): string
|
public static function base64_url_encode(string $input): string
|
||||||
{
|
{
|
||||||
return strtr(base64_encode($input), '+/', '-_');
|
return rtrim(strtr(base64_encode($input), '+/', '-_'), '=');
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @throws UrlException */
|
/** @throws UrlException */
|
||||||
|
|||||||
@@ -36,4 +36,13 @@ class CandidateRepository extends ServiceEntityRepository
|
|||||||
->setParameter('name', $name)
|
->setParameter('name', $name)
|
||||||
->getQuery()->getOneOrNullResult();
|
->getQuery()->getOneOrNullResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function save(Candidate $candidate, bool $flush = true): void
|
||||||
|
{
|
||||||
|
$this->getEntityManager()->persist($candidate);
|
||||||
|
|
||||||
|
if (true === $flush) {
|
||||||
|
$this->getEntityManager()->flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,4 +17,13 @@ class GivenAnswerRepository extends ServiceEntityRepository
|
|||||||
{
|
{
|
||||||
parent::__construct($registry, GivenAnswer::class);
|
parent::__construct($registry, GivenAnswer::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function save(GivenAnswer $givenAnswer, bool $flush = true): void
|
||||||
|
{
|
||||||
|
$this->getEntityManager()->persist($givenAnswer);
|
||||||
|
|
||||||
|
if (true === $flush) {
|
||||||
|
$this->getEntityManager()->flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,13 +20,13 @@ class QuestionRepository extends ServiceEntityRepository
|
|||||||
parent::__construct($registry, Question::class);
|
parent::__construct($registry, Question::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function findNextQuestionForCandidate(Candidate $candidate): Question
|
public function findNextQuestionForCandidate(Candidate $candidate): ?Question
|
||||||
{
|
{
|
||||||
$qb = $this->createQueryBuilder('q');
|
$qb = $this->createQueryBuilder('q');
|
||||||
|
|
||||||
return $qb->join('q.quiz', 'qz')
|
return $qb->join('q.quiz', 'qz')
|
||||||
->andWhere($qb->expr()->notIn('q.id', $this->getEntityManager()->createQueryBuilder()
|
->andWhere($qb->expr()->notIn('q.id', $this->getEntityManager()->createQueryBuilder()
|
||||||
->select('ga.id')
|
->select('q1')
|
||||||
->from(GivenAnswer::class, 'ga')
|
->from(GivenAnswer::class, 'ga')
|
||||||
->join('ga.answer', 'a')
|
->join('ga.answer', 'a')
|
||||||
->join('a.question', 'q1')
|
->join('a.question', 'q1')
|
||||||
@@ -38,6 +38,6 @@ class QuestionRepository extends ServiceEntityRepository
|
|||||||
->setMaxResults(1)
|
->setMaxResults(1)
|
||||||
->setParameter('candidate', $candidate)
|
->setParameter('candidate', $candidate)
|
||||||
->setParameter('quiz', $candidate->getSeason()->getActiveQuiz())
|
->setParameter('quiz', $candidate->getSeason()->getActiveQuiz())
|
||||||
->getQuery()->getSingleResult();
|
->getQuery()->getOneOrNullResult();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,16 @@
|
|||||||
Candiadte: {{ candidate.name }}<br/>
|
Candiadte: {{ candidate.name }}<br/>
|
||||||
|
|
||||||
{{ question.question }}<br/>
|
{{ question.question }}<br/>
|
||||||
{% for answer in question.answers %}
|
<form method="post">
|
||||||
<input type="radio" name="answer" value="{{ answer.id }}"> {{ answer.text }}
|
{% for answer in question.answers %}
|
||||||
{% endfor %}
|
<div>
|
||||||
|
<button class="btn btn-outline-success"
|
||||||
|
type="submit"
|
||||||
|
name="answer"
|
||||||
|
value="{{ answer.id }}">{{ answer.text }}</button>
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
Weirdly enough this question has no answers...
|
||||||
|
{% endfor %}
|
||||||
|
</form>
|
||||||
{% endblock body %}
|
{% endblock body %}
|
||||||
|
|||||||
Reference in New Issue
Block a user