mirror of
https://github.com/MarijnDoeve/TijdVoorDeTest.git
synced 2026-03-07 13:14:20 +01:00
Compare commits
2 Commits
29bc74fe4f
...
f7b4b98da4
| Author | SHA1 | Date | |
|---|---|---|---|
|
f7b4b98da4
|
|||
|
0ccce51af8
|
@@ -33,6 +33,7 @@ indent_size = 4
|
||||
|
||||
[*.{yaml,yml}]
|
||||
trim_trailing_whitespace = false
|
||||
indent_size = 2
|
||||
|
||||
[.github/workflows/*.yml]
|
||||
indent_size = 2
|
||||
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -105,3 +105,7 @@ phpstan.neon
|
||||
/phpunit.xml
|
||||
.phpunit.result.cache
|
||||
###< phpunit/phpunit ###
|
||||
|
||||
###> vincentlanglet/twig-cs-fixer ###
|
||||
/.twig-cs-fixer.cache
|
||||
###< vincentlanglet/twig-cs-fixer ###
|
||||
|
||||
3
.idea/TijdVoorDeTest.iml
generated
3
.idea/TijdVoorDeTest.iml
generated
@@ -85,7 +85,6 @@
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-intl-grapheme" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-intl-normalizer" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-mbstring" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-php83" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/process" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/routing" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/runtime" />
|
||||
@@ -133,6 +132,8 @@
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/twig/html-extra" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/data-fixtures" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/doctrine-fixtures-bundle" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/vincentlanglet/twig-cs-fixer" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/webmozart/assert" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
|
||||
3
.idea/php.xml
generated
3
.idea/php.xml
generated
@@ -46,7 +46,6 @@
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/finder" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/runtime" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/routing" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-php83" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/event-dispatcher" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/var-exporter" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/cache" />
|
||||
@@ -163,6 +162,8 @@
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/translation" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/data-fixtures" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/doctrine-fixtures-bundle" />
|
||||
<path value="$PROJECT_DIR$/vendor/webmozart/assert" />
|
||||
<path value="$PROJECT_DIR$/vendor/vincentlanglet/twig-cs-fixer" />
|
||||
</include_path>
|
||||
</component>
|
||||
<component name="PhpInterpreters">
|
||||
|
||||
10
.idea/phpunit.xml
generated
Normal file
10
.idea/phpunit.xml
generated
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="PHPUnit">
|
||||
<option name="directories">
|
||||
<list>
|
||||
<option value="$PROJECT_DIR$/tests" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
@@ -67,6 +67,8 @@ RUN set -eux; \
|
||||
|
||||
COPY --link frankenphp/conf.d/20-app.dev.ini $PHP_INI_DIR/app.conf.d/
|
||||
|
||||
RUN git config --global --add safe.directory /app
|
||||
|
||||
CMD [ "frankenphp", "run", "--config", "/etc/caddy/Caddyfile", "--watch" ]
|
||||
|
||||
# Prod FrankenPHP image
|
||||
|
||||
20
Taskfile.yml
Normal file
20
Taskfile.yml
Normal file
@@ -0,0 +1,20 @@
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
up:
|
||||
cmds:
|
||||
- docker compose up -d
|
||||
down:
|
||||
cmds:
|
||||
- docker compose down
|
||||
stop:
|
||||
cmds:
|
||||
- docker compose stop
|
||||
shell:
|
||||
cmds:
|
||||
- docker compose exec app bash
|
||||
migrate:
|
||||
cmds:
|
||||
- docker compose run php bin/console doctrine:migrations:migrate
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "symfony/skeleton",
|
||||
"name": "MarijnDoeve/TijdVoorDeTest",
|
||||
"type": "project",
|
||||
"license": "MIT",
|
||||
"description": "A minimal Symfony project recommended to create bare bones applications",
|
||||
@@ -9,16 +9,16 @@
|
||||
"php": ">=8.3.15",
|
||||
"ext-ctype": "*",
|
||||
"ext-iconv": "*",
|
||||
"doctrine/dbal": "^3",
|
||||
"doctrine/doctrine-bundle": "^2.13",
|
||||
"doctrine/doctrine-migrations-bundle": "^3.3",
|
||||
"doctrine/orm": "^3.3",
|
||||
"easycorp/easyadmin-bundle": "^4.23",
|
||||
"doctrine/dbal": "^4.2.2",
|
||||
"doctrine/doctrine-bundle": "^2.13.2",
|
||||
"doctrine/doctrine-migrations-bundle": "^3.4.1",
|
||||
"doctrine/orm": "^3.3.2",
|
||||
"easycorp/easyadmin-bundle": "^4.24.4",
|
||||
"runtime/frankenphp-symfony": "^0.2.0",
|
||||
"symfony/asset": "7.2.*",
|
||||
"symfony/console": "7.2.*",
|
||||
"symfony/dotenv": "7.2.*",
|
||||
"symfony/flex": "^2.4.7",
|
||||
"symfony/flex": "^2.5.0",
|
||||
"symfony/form": "7.2.*",
|
||||
"symfony/framework-bundle": "7.2.*",
|
||||
"symfony/runtime": "7.2.*",
|
||||
@@ -29,19 +29,21 @@
|
||||
"thecodingmachine/safe": "^2.5"
|
||||
},
|
||||
"require-dev": {
|
||||
"roave/security-advisories": "dev-latest",
|
||||
"doctrine/doctrine-fixtures-bundle": "^4.0",
|
||||
"friendsofphp/php-cs-fixer": "^3.65",
|
||||
"phpstan/extension-installer": "^1.4",
|
||||
"phpstan/phpstan": "^2.0",
|
||||
"phpstan/phpstan-doctrine": "^2.0",
|
||||
"phpstan/phpstan-phpunit": "^2.0",
|
||||
"phpstan/phpstan-symfony": "^2.0",
|
||||
"phpunit/phpunit": "^11",
|
||||
"rector/rector": "^2.0",
|
||||
"friendsofphp/php-cs-fixer": "^3.70.2",
|
||||
"phpstan/extension-installer": "^1.4.3",
|
||||
"phpstan/phpstan": "^2.1.7",
|
||||
"phpstan/phpstan-doctrine": "^2.0.2",
|
||||
"phpstan/phpstan-phpunit": "^2.0.4",
|
||||
"phpstan/phpstan-symfony": "^2.0.2",
|
||||
"phpunit/phpunit": "^11.5.11",
|
||||
"rector/rector": "^2.0.10",
|
||||
"symfony/maker-bundle": "^1.62.1",
|
||||
"symfony/stopwatch": "7.2.*",
|
||||
"symfony/web-profiler-bundle": "7.2.*",
|
||||
"thecodingmachine/phpstan-safe-rule": "^1.3"
|
||||
"thecodingmachine/phpstan-safe-rule": "^1.4",
|
||||
"vincentlanglet/twig-cs-fixer": "^3.5.1"
|
||||
},
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
@@ -71,7 +73,8 @@
|
||||
"symfony/polyfill-php74": "*",
|
||||
"symfony/polyfill-php80": "*",
|
||||
"symfony/polyfill-php81": "*",
|
||||
"symfony/polyfill-php82": "*"
|
||||
"symfony/polyfill-php82": "*",
|
||||
"symfony/polyfill-php83": "*"
|
||||
},
|
||||
"scripts": {
|
||||
"auto-scripts": {
|
||||
|
||||
1521
composer.lock
generated
1521
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
Symfony\Bundle\FrameworkBundle\FrameworkBundle::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
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Admin;
|
||||
|
||||
use App\Entity\Answer;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Admin;
|
||||
|
||||
use App\Entity\Candidate;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Admin;
|
||||
|
||||
use App\Entity\Correction;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Admin;
|
||||
|
||||
use App\Entity\GivenAnswer;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Admin;
|
||||
|
||||
use App\Entity\Question;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Admin;
|
||||
|
||||
use App\Entity\Quiz;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Admin;
|
||||
|
||||
use App\Entity\Season;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Admin;
|
||||
|
||||
use App\Entity\User;
|
||||
|
||||
@@ -4,15 +4,21 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Entity\Answer;
|
||||
use App\Entity\Candidate;
|
||||
use App\Entity\GivenAnswer;
|
||||
use App\Entity\Question;
|
||||
use App\Entity\Season;
|
||||
use App\Enum\FlashType;
|
||||
use App\Form\EnterNameType;
|
||||
use App\Form\SelectSeasonType;
|
||||
use App\Helpers\Base64;
|
||||
use App\Repository\AnswerRepository;
|
||||
use App\Repository\CandidateRepository;
|
||||
use App\Repository\GivenAnswerRepository;
|
||||
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\Response;
|
||||
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])]
|
||||
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 (true === $season->isPreregisterCandidates()) {
|
||||
$this->addFlash(FlashType::Danger, 'Candidate not found');
|
||||
|
||||
return $this->redirectToRoute('enter_name', ['seasonCode' => $season->getSeasonCode()]);
|
||||
}
|
||||
|
||||
$candidate = new Candidate(Base64::base64_url_decode($nameHash));
|
||||
$candidateRepository->save($candidate);
|
||||
}
|
||||
|
||||
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())
|
||||
->setCandidate($candidate)
|
||||
->setAnswer($answer);
|
||||
$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()]);
|
||||
}
|
||||
|
||||
// TODO One first question record time
|
||||
return $this->render('quiz/question.twig', ['candidate' => $candidate, 'question' => $question]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ class KrtekFixtures extends Fixture
|
||||
->addAnswer(new Answer('Met de auto'))
|
||||
)
|
||||
->addQuestion((new Question())
|
||||
->setQuestion('Met wie keek de Kretek video bij binnenkomst?')
|
||||
->setQuestion('Met wie keek de Krtek video bij binnenkomst?')
|
||||
->addAnswer(new Answer('Claudia'))
|
||||
->addAnswer(new Answer('Eelco'))
|
||||
->addAnswer(new Answer('Elise'))
|
||||
|
||||
@@ -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';
|
||||
}
|
||||
|
||||
@@ -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
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,5 +250,14 @@
|
||||
},
|
||||
"twig/extra-bundle": {
|
||||
"version": "v3.18.0"
|
||||
},
|
||||
"vincentlanglet/twig-cs-fixer": {
|
||||
"version": "3.5",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes-contrib",
|
||||
"branch": "main",
|
||||
"version": "3.0",
|
||||
"ref": "d42582ae1bce86fd43491d6264c738b0867f8ffe"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends "quiz/base.html.twig" %}
|
||||
{% extends 'quiz/base.html.twig' %}
|
||||
{% block body %}
|
||||
{{ season.name }}
|
||||
{{ form(form) }}
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
{% extends "quiz/base.html.twig" %}
|
||||
{% extends 'quiz/base.html.twig' %}
|
||||
{% block body %}
|
||||
Candiadte: {{ candidate.name }}<br/>
|
||||
|
||||
{{ question.question }}<br/>
|
||||
<form method="post">
|
||||
{% for answer in question.answers %}
|
||||
<input type="radio" name="answer" value="{{ answer.id }}"> {{ answer.text }}
|
||||
<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 %}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends "quiz/base.html.twig" %}
|
||||
{% extends 'quiz/base.html.twig' %}
|
||||
{% block body %}
|
||||
{{ form(form) }}
|
||||
{% endblock body %}
|
||||
|
||||
Reference in New Issue
Block a user