mirror of
https://github.com/MarijnDoeve/TijdVoorDeTest.git
synced 2026-03-06 04:44:19 +01:00
Implement flash messages, refactor candidate retrieval, and enhance quiz functionality
This commit is contained in:
@@ -4,11 +4,14 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Controller;
|
namespace App\Controller;
|
||||||
|
|
||||||
|
use App\Entity\Candidate;
|
||||||
use App\Entity\Season;
|
use App\Entity\Season;
|
||||||
|
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 Safe\Exceptions\UrlException;
|
use App\Repository\CandidateRepository;
|
||||||
|
use App\Repository\QuestionRepository;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
@@ -60,13 +63,23 @@ class QuizController extends AbstractController
|
|||||||
name: 'quiz_page',
|
name: 'quiz_page',
|
||||||
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(Season $season, string $nameHash)
|
public function quizPage(
|
||||||
{
|
Season $season,
|
||||||
try {
|
string $nameHash,
|
||||||
$name = Base64::base64_url_decode($nameHash);
|
CandidateRepository $candidateRepository,
|
||||||
} catch (UrlException $e) {
|
QuestionRepository $questionRepository,
|
||||||
|
): 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');
|
||||||
|
|
||||||
|
return $this->redirectToRoute('enter_name', ['seasonCode' => $season->getSeasonCode()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->render('quiz/question.twig', ['season' => $season, 'name' => $name]);
|
$question = $questionRepository->findNextQuestionForCandidate($candidate);
|
||||||
|
|
||||||
|
return $this->render('quiz/question.twig', ['candidate' => $candidate, 'question' => $question]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,8 +34,10 @@ class KrtekFixtures extends Fixture
|
|||||||
->addCandidate(new Candidate('Philine'))
|
->addCandidate(new Candidate('Philine'))
|
||||||
->addCandidate(new Candidate('Remy'))
|
->addCandidate(new Candidate('Remy'))
|
||||||
->addCandidate(new Candidate('Robbert'))
|
->addCandidate(new Candidate('Robbert'))
|
||||||
->addCandidate(new Candidate('Tom'))
|
->addCandidate(new Candidate('Tom'));
|
||||||
->addQuiz($this->createQuiz1($season))
|
$quiz1 = $this->createQuiz1($season);
|
||||||
|
$season->addQuiz($quiz1)
|
||||||
|
->setActiveQuiz($quiz1)
|
||||||
->addQuiz($this->createQuiz2($season));
|
->addQuiz($this->createQuiz2($season));
|
||||||
|
|
||||||
$manager->flush();
|
$manager->flush();
|
||||||
@@ -49,8 +51,8 @@ class KrtekFixtures extends Fixture
|
|||||||
|
|
||||||
->addQuestion((new Question())
|
->addQuestion((new Question())
|
||||||
->setQuestion('Is de Krtek een man of een vrouw?')
|
->setQuestion('Is de Krtek een man of een vrouw?')
|
||||||
->addAnswer(new Answer('Ja', true))
|
->addAnswer(new Answer('Vrouw', true))
|
||||||
->addAnswer(new Answer('Nee'))
|
->addAnswer(new Answer('Man'))
|
||||||
)
|
)
|
||||||
|
|
||||||
->addQuestion((new Question())
|
->addQuestion((new Question())
|
||||||
|
|||||||
17
src/Enum/FlashType.php
Normal file
17
src/Enum/FlashType.php
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Enum;
|
||||||
|
|
||||||
|
enum FlashType: string
|
||||||
|
{
|
||||||
|
case Primary = 'primary';
|
||||||
|
case Secondary = 'secondary';
|
||||||
|
case Success = 'success';
|
||||||
|
case Danger = 'danger';
|
||||||
|
case Warning = 'warning';
|
||||||
|
case Info = 'info';
|
||||||
|
case Ligt = 'light';
|
||||||
|
case Dark = 'dark';
|
||||||
|
}
|
||||||
@@ -14,12 +14,12 @@ 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 strtr(base64_encode($input), '+/', '-_');
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @throws UrlException */
|
/** @throws UrlException */
|
||||||
public static function base64_url_decode(string $input): string
|
public static function base64_url_decode(string $input): string
|
||||||
{
|
{
|
||||||
return \Safe\base64_decode(strtr($input, '-_.', '+/='), true);
|
return \Safe\base64_decode(strtr($input, '-_', '+/'), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,11 @@ class CandidateRepository extends ServiceEntityRepository
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->findOneBy(['season' => $season, 'name' => $name]);
|
return $this->createQueryBuilder('c')
|
||||||
|
->where('c.season = :season')
|
||||||
|
->andWhere('lower(c.name) = lower(:name)')
|
||||||
|
->setParameter('season', $season)
|
||||||
|
->setParameter('name', $name)
|
||||||
|
->getQuery()->getOneOrNullResult();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Repository;
|
namespace App\Repository;
|
||||||
|
|
||||||
|
use App\Entity\Candidate;
|
||||||
|
use App\Entity\GivenAnswer;
|
||||||
use App\Entity\Question;
|
use App\Entity\Question;
|
||||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||||
use Doctrine\Persistence\ManagerRegistry;
|
use Doctrine\Persistence\ManagerRegistry;
|
||||||
@@ -17,4 +19,25 @@ class QuestionRepository extends ServiceEntityRepository
|
|||||||
{
|
{
|
||||||
parent::__construct($registry, Question::class);
|
parent::__construct($registry, Question::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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')
|
||||||
|
->from(GivenAnswer::class, 'ga')
|
||||||
|
->join('ga.answer', 'a')
|
||||||
|
->join('a.question', 'q1')
|
||||||
|
->andWhere($qb->expr()->isNotNull('ga.answer'))
|
||||||
|
->andWhere('ga.candidate = :candidate')
|
||||||
|
->andWhere('q1.quiz = :quiz')
|
||||||
|
->getDQL()))
|
||||||
|
->andWhere('qz = :quiz')
|
||||||
|
->setMaxResults(1)
|
||||||
|
->setParameter('candidate', $candidate)
|
||||||
|
->setParameter('quiz', $candidate->getSeason()->getActiveQuiz())
|
||||||
|
->getQuery()->getSingleResult();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,14 @@
|
|||||||
<body>
|
<body>
|
||||||
<main>
|
<main>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
{% for label, messages in app.flashes() %}
|
||||||
|
{% for message in messages %}
|
||||||
|
<div class="alert alert-{{ label }} alert-dismissible " role="alert">
|
||||||
|
{{ message }}
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% endfor %}
|
||||||
{% block body %}
|
{% block body %}
|
||||||
{% endblock body %}
|
{% endblock body %}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
{% extends "quiz/base.html.twig" %}
|
{% extends "quiz/base.html.twig" %}
|
||||||
{% block body %}
|
{% block body %}
|
||||||
{{ season.name }}
|
Candiadte: {{ candidate.name }}<br/>
|
||||||
{{ name }}
|
|
||||||
<h1>Hello World!</h1>
|
{{ question.question }}<br/>
|
||||||
|
{% for answer in question.answers %}
|
||||||
|
<input type="radio" name="answer" value="{{ answer.id }}"> {{ answer.text }}
|
||||||
|
{% endfor %}
|
||||||
{% endblock body %}
|
{% endblock body %}
|
||||||
|
|||||||
Reference in New Issue
Block a user