mirror of
https://github.com/MarijnDoeve/TijdVoorDeTest.git
synced 2026-03-05 20:44:19 +01:00
Merge branch 'main' of github.com:MarijnDoeve/TijdVoorDeTest
This commit is contained in:
48
migrations/Version20250610210417.php
Normal file
48
migrations/Version20250610210417.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
final class Version20250610210417 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$this->addSql(<<<'SQL'
|
||||
CREATE TABLE season_settings (id UUID NOT NULL, show_numbers BOOLEAN DEFAULT false NOT NULL, confirm_answers BOOLEAN DEFAULT false NOT NULL, PRIMARY KEY(id))
|
||||
SQL);
|
||||
$this->addSql(<<<'SQL'
|
||||
ALTER TABLE season ADD settings_id UUID DEFAULT NULL
|
||||
SQL);
|
||||
$this->addSql(<<<'SQL'
|
||||
ALTER TABLE season ADD CONSTRAINT FK_F0E45BA959949888 FOREIGN KEY (settings_id) REFERENCES season_settings (id) NOT DEFERRABLE INITIALLY IMMEDIATE
|
||||
SQL);
|
||||
$this->addSql(<<<'SQL'
|
||||
CREATE UNIQUE INDEX UNIQ_F0E45BA959949888 ON season (settings_id)
|
||||
SQL);
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql(<<<'SQL'
|
||||
DROP TABLE season_settings
|
||||
SQL);
|
||||
$this->addSql(<<<'SQL'
|
||||
ALTER TABLE season DROP CONSTRAINT FK_F0E45BA959949888
|
||||
SQL);
|
||||
$this->addSql(<<<'SQL'
|
||||
DROP INDEX UNIQ_F0E45BA959949888
|
||||
SQL);
|
||||
$this->addSql(<<<'SQL'
|
||||
ALTER TABLE season DROP settings_id
|
||||
SQL);
|
||||
}
|
||||
}
|
||||
40
src/Command/AddSettingsCommand.php
Normal file
40
src/Command/AddSettingsCommand.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
use App\Entity\SeasonSettings;
|
||||
use App\Repository\SeasonRepository;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
#[AsCommand(
|
||||
name: 'app:add-settings',
|
||||
description: 'Add a short description for your command',
|
||||
)]
|
||||
readonly class AddSettingsCommand
|
||||
{
|
||||
public function __construct(private SeasonRepository $seasonRepository, private EntityManagerInterface $entityManager) {}
|
||||
|
||||
public function __invoke(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
foreach ($this->seasonRepository->findAll() as $season) {
|
||||
if (null !== $season->getSettings()) {
|
||||
continue;
|
||||
}
|
||||
$io->text('Adding settings to season : '.$season->getSeasonCode());
|
||||
$season->setSettings(new SeasonSettings());
|
||||
}
|
||||
|
||||
$this->entityManager->flush();
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ use App\Entity\Quiz;
|
||||
use App\Entity\Season;
|
||||
use App\Enum\FlashType;
|
||||
use App\Form\AddCandidatesFormType;
|
||||
use App\Form\SettingsForm;
|
||||
use App\Form\UploadQuizFormType;
|
||||
use App\Security\Voter\SeasonVoter;
|
||||
use App\Service\QuizSpreadsheetService;
|
||||
@@ -26,7 +27,9 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
#[IsGranted('ROLE_USER')]
|
||||
class SeasonController extends AbstractController
|
||||
{
|
||||
public function __construct(private readonly TranslatorInterface $translator, private readonly EntityManagerInterface $em,
|
||||
public function __construct(
|
||||
private readonly TranslatorInterface $translator,
|
||||
private readonly EntityManagerInterface $em,
|
||||
) {}
|
||||
|
||||
#[Route(
|
||||
@@ -35,10 +38,19 @@ class SeasonController extends AbstractController
|
||||
requirements: ['seasonCode' => self::SEASON_CODE_REGEX],
|
||||
)]
|
||||
#[IsGranted(SeasonVoter::EDIT, subject: 'season')]
|
||||
public function index(Season $season): Response
|
||||
public function index(Season $season, Request $request): Response
|
||||
{
|
||||
$form = $this->createForm(SettingsForm::class, $season->getSettings());
|
||||
|
||||
$form->handleRequest($request);
|
||||
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
$this->em->flush();
|
||||
}
|
||||
|
||||
return $this->render('backoffice/season.html.twig', [
|
||||
'season' => $season,
|
||||
'form' => $form,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -125,6 +125,6 @@ final class QuizController extends AbstractController
|
||||
|
||||
$quizCandidateRepository->createIfNotExist($quiz, $candidate);
|
||||
|
||||
return $this->render('quiz/question.twig', ['candidate' => $candidate, 'question' => $question]);
|
||||
return $this->render('quiz/question.twig', ['candidate' => $candidate, 'question' => $question, 'season' => $season]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,8 +46,13 @@ class Season
|
||||
#[ORM\JoinColumn(nullable: true, onDelete: 'SET NULL')]
|
||||
private ?Quiz $ActiveQuiz = null;
|
||||
|
||||
#[ORM\OneToOne(cascade: ['persist', 'remove'])]
|
||||
#[ORM\JoinColumn(nullable: true)]
|
||||
private ?SeasonSettings $settings = null;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->settings = new SeasonSettings();
|
||||
$this->quizzes = new ArrayCollection();
|
||||
$this->candidates = new ArrayCollection();
|
||||
$this->owners = new ArrayCollection();
|
||||
@@ -166,4 +171,16 @@ class Season
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSettings(): ?SeasonSettings
|
||||
{
|
||||
return $this->settings;
|
||||
}
|
||||
|
||||
public function setSettings(SeasonSettings $settings): static
|
||||
{
|
||||
$this->settings = $settings;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
57
src/Entity/SeasonSettings.php
Normal file
57
src/Entity/SeasonSettings.php
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Repository\SeasonSettingsRepository;
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator;
|
||||
use Symfony\Bridge\Doctrine\Types\UuidType;
|
||||
use Symfony\Component\Uid\Uuid;
|
||||
|
||||
#[ORM\Entity(repositoryClass: SeasonSettingsRepository::class)]
|
||||
class SeasonSettings
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
|
||||
#[ORM\Column(type: UuidType::NAME)]
|
||||
#[ORM\CustomIdGenerator(class: UuidGenerator::class)]
|
||||
private Uuid $id;
|
||||
|
||||
#[ORM\Column(type: Types::BOOLEAN, options: ['default' => false])]
|
||||
private bool $showNumbers = false;
|
||||
|
||||
#[ORM\Column(type: Types::BOOLEAN, options: ['default' => false])]
|
||||
private bool $confirmAnswers = false;
|
||||
|
||||
public function getId(): Uuid
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function isShowNumbers(): bool
|
||||
{
|
||||
return $this->showNumbers;
|
||||
}
|
||||
|
||||
public function setShowNumbers(bool $showNumbers): self
|
||||
{
|
||||
$this->showNumbers = $showNumbers;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isConfirmAnswers(): bool
|
||||
{
|
||||
return $this->confirmAnswers;
|
||||
}
|
||||
|
||||
public function setConfirmAnswers(bool $confirmAnswers): self
|
||||
{
|
||||
$this->confirmAnswers = $confirmAnswers;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
35
src/Form/SettingsForm.php
Normal file
35
src/Form/SettingsForm.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Form;
|
||||
|
||||
use App\Entity\SeasonSettings;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
/** @extends AbstractType<SeasonSettings> */
|
||||
class SettingsForm extends AbstractType
|
||||
{
|
||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||
{
|
||||
$builder
|
||||
->add('showNumbers', options: [
|
||||
'label_attr' => ['class' => 'checkbox-switch'],
|
||||
'attr' => ['role' => 'switch', 'switch' => null]])
|
||||
->add('confirmAnswers', options: [
|
||||
'label_attr' => ['class' => 'checkbox-switch'],
|
||||
'attr' => ['role' => 'switch', 'switch' => null]])
|
||||
->add('save', SubmitType::class)
|
||||
;
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver): void
|
||||
{
|
||||
$resolver->setDefaults([
|
||||
'data_class' => SeasonSettings::class,
|
||||
]);
|
||||
}
|
||||
}
|
||||
20
src/Repository/SeasonSettingsRepository.php
Normal file
20
src/Repository/SeasonSettingsRepository.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Repository;
|
||||
|
||||
use App\Entity\SeasonSettings;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @extends ServiceEntityRepository<SeasonSettings>
|
||||
*/
|
||||
class SeasonSettingsRepository extends ServiceEntityRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, SeasonSettings::class);
|
||||
}
|
||||
}
|
||||
@@ -21,13 +21,18 @@
|
||||
<div class="d-flex flex-row align-items-center">
|
||||
<h4 class="py-2 pe-2">{{ 'Candidates'|trans }}</h4>
|
||||
<a class="link"
|
||||
href="{{ path('app_backoffice_add_candidates', {seasonCode: season.seasonCode}) }}">{{ 'Add Candidate'|trans }}</a>
|
||||
|
||||
href="{{ path('app_backoffice_add_candidates', {seasonCode: season.seasonCode}) }}">{{ 'Add Candidate'|trans }}
|
||||
</a>
|
||||
</div>
|
||||
<ul>
|
||||
{% for candidate in season.candidates %}
|
||||
<li>{{ candidate.name }}</li>{% endfor %}
|
||||
</ul>
|
||||
|
||||
<div class="d-flex flex-row align-items-center">
|
||||
<h4 class="py-2 pe-2">{{ 'Settings'|trans }}</h4>
|
||||
</div>
|
||||
{{ form(form) }}
|
||||
</div>
|
||||
<div class="col-12 col-md-3"></div>
|
||||
</div>
|
||||
|
||||
@@ -1,17 +1,35 @@
|
||||
{% extends 'quiz/base.html.twig' %}
|
||||
{% block body %}
|
||||
{{ question.question }}<br/>
|
||||
<h4>
|
||||
{% if season.settings.showNumbers %}
|
||||
({{ question.ordering }}/{{ question.quiz.questions.count }})
|
||||
{% endif %}{{ question.question }}<br/>
|
||||
</h4>
|
||||
<form method="post">
|
||||
<input type="hidden" name="token" value="{{ csrf_token('question') }}">
|
||||
{% for answer in question.answers %}
|
||||
<div>
|
||||
<button class="btn btn-outline-success"
|
||||
type="submit"
|
||||
name="answer"
|
||||
value="{{ answer.id }}">{{ answer.text }}</button>
|
||||
</div>
|
||||
{% if season.settings.confirmAnswers == false %}
|
||||
{% for answer in question.answers %}
|
||||
<div class="py-2">
|
||||
<button class="btn btn-outline-success"
|
||||
type="submit"
|
||||
name="answer"
|
||||
value="{{ answer.id }}">{{ answer.text }}</button>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
Weirdly enough this question has no answers...
|
||||
{% endfor %}
|
||||
{% for answer in question.answers %}
|
||||
<div class="py-1">
|
||||
<input type="radio" class="btn-check" name="answer" id="answer-{{ loop.index0 }}" autocomplete="off"
|
||||
value="{{ answer.id }}">
|
||||
<label class="btn btn-outline-secondary" for="answer-{{ loop.index0 }}">{{ answer.text }}</label>
|
||||
</div>
|
||||
{% endfor %}
|
||||
<div class="py-2">
|
||||
<button class="btn btn-success"
|
||||
type="submit"
|
||||
>{{ 'Next'|trans }}</button>
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
</form>
|
||||
{% endblock body %}
|
||||
|
||||
@@ -153,6 +153,10 @@
|
||||
<source>No</source>
|
||||
<target>Nee</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="gefhnBC" resname="Next">
|
||||
<source>Next</source>
|
||||
<target>Volgende</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="nOHriCl" resname="No active quiz">
|
||||
<source>No active quiz</source>
|
||||
<target>Geen actieve test</target>
|
||||
@@ -273,6 +277,10 @@
|
||||
<source>Seasons</source>
|
||||
<target>Seizoenen</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="VXFwlwn" resname="Settings">
|
||||
<source>Settings</source>
|
||||
<target>Instellingen</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="pNIxNSX" resname="Sign in">
|
||||
<source>Sign in</source>
|
||||
<target>Log in</target>
|
||||
|
||||
Reference in New Issue
Block a user