trial app
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Entity\Test;
|
||||
use App\Entity\UserAnswer;
|
||||
use App\Form\Type\UserAnswerType;
|
||||
use App\Service\QuestionService;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\Form\FormInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
use Symfony\Component\Uid\Factory\UuidFactory;
|
||||
|
||||
class IndexController extends AbstractController
|
||||
{
|
||||
|
||||
public function __construct(
|
||||
private readonly QuestionService $questionService,
|
||||
private readonly UuidFactory $uuidFactory,
|
||||
private readonly RequestStack $requestStack,
|
||||
private readonly EntityManagerInterface $em
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
#[Route('/', name: 'index')]
|
||||
public function index(Request $request): Response
|
||||
{
|
||||
$test = $this->em->getRepository(Test::class)->find(1);
|
||||
$session = $request->getSession();
|
||||
|
||||
if (!$session->has('step')) {
|
||||
$step = $this->getStep($test, $this->getUuid());
|
||||
$session->set('step', $step);
|
||||
}
|
||||
$step = $session->get('step');
|
||||
|
||||
$form = $this->getForm($test, $step);
|
||||
|
||||
if ($request->getMethod() === 'POST') {
|
||||
$form->handleRequest($request);
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
$this->em->flush();
|
||||
if ($step = $this->getStep($test, $this->getUuid())) {
|
||||
$session->set('step', $step);
|
||||
$form = $this->getForm($test, $step);
|
||||
} else {
|
||||
$session->set('test_' . $test->getId(), true);
|
||||
$session->remove('step');
|
||||
$oldUuid = $this->getUuid();
|
||||
$this->getUuid(true);
|
||||
return $this->redirectToRoute('test_results', ['test_id' => $test->getId(), 'uuid' => $oldUuid]);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return $this->render('index/index.html.twig', ['form' => $form, 'test' => $test, 'step' => $step - 1]);
|
||||
}
|
||||
|
||||
#[Route('/test_results/{test_id}/{uuid}', name: 'test_results', requirements: ['test_id' => '\d+'])]
|
||||
public function testResults(EntityManagerInterface $em, int $test_id, string $uuid): Response
|
||||
{
|
||||
$test = $em->getRepository(Test::class)->find($test_id);
|
||||
if (!$test) {
|
||||
$this->redirectToRoute('index');
|
||||
}
|
||||
|
||||
$existingAnswers = $this->em->getRepository(UserAnswer::class)->findBy(['uuid' => $uuid]);
|
||||
if (count($existingAnswers) != $test->getQuestions()->count()) {
|
||||
$this->redirectToRoute('index');
|
||||
}
|
||||
|
||||
return $this->render('index/results.html.twig',[
|
||||
'test' => $test,
|
||||
'existingAnswers' => $existingAnswers,
|
||||
'service' => $this->questionService,
|
||||
'uuid' => $uuid,
|
||||
]);
|
||||
}
|
||||
|
||||
private function getForm(Test $test, $step): FormInterface
|
||||
{
|
||||
$question = $test->getQuestions()->findFirst(fn($i, $q) => $q->getId() === $step);
|
||||
$questionModel = $this->questionService->getQuestionModel($question);
|
||||
$userAnswer = (new UserAnswer())->setQuestion($question)->setUuid($this->getUuid());
|
||||
$this->em->persist($userAnswer);
|
||||
|
||||
return $this->createForm(UserAnswerType::class, $userAnswer, [
|
||||
'questionModel' => $questionModel,
|
||||
'question' => $question,
|
||||
'test' => $test,
|
||||
]);
|
||||
}
|
||||
|
||||
private function getUuid($forceNew = false)
|
||||
{
|
||||
$session = $this->requestStack->getCurrentRequest()->getSession();
|
||||
if (!$session->has('uuid') || $forceNew) {
|
||||
$uuid = $this->uuidFactory->create();
|
||||
$session->set('uuid', $uuid);
|
||||
} else {
|
||||
$uuid = $session->get('uuid');
|
||||
}
|
||||
|
||||
return $uuid;
|
||||
}
|
||||
|
||||
private function getStep(Test $test, string $uuid): int
|
||||
{
|
||||
$existingAnswers = array_map(fn($a) => $a->getQuestion()->getId(), $this->em->getRepository(UserAnswer::class)->findBy(['uuid' => $uuid]));
|
||||
$allSteps = $test->getQuestions()->map(fn($q) => $q->getId())->toArray();
|
||||
$availableSteps = array_diff($allSteps, $existingAnswers);
|
||||
shuffle($availableSteps);
|
||||
|
||||
return current($availableSteps);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Repository\QuestionRepository;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
#[ORM\Entity(repositoryClass: QuestionRepository::class)]
|
||||
class Question
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue]
|
||||
#[ORM\Column]
|
||||
private ?int $id = null;
|
||||
|
||||
#[ORM\Column]
|
||||
private array $prompt = [];
|
||||
|
||||
#[ORM\Column]
|
||||
private array $answers = [];
|
||||
|
||||
#[ORM\ManyToOne(inversedBy: 'questions')]
|
||||
#[ORM\JoinColumn(nullable: false)]
|
||||
private Test $test;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getPrompt(): array
|
||||
{
|
||||
return $this->prompt;
|
||||
}
|
||||
|
||||
public function setPrompt(array $prompt): static
|
||||
{
|
||||
$this->prompt = $prompt;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAnswers(): array
|
||||
{
|
||||
return $this->answers;
|
||||
}
|
||||
|
||||
public function setAnswers(array $answers): static
|
||||
{
|
||||
$this->answers = $answers;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTest(): Test
|
||||
{
|
||||
return $this->test;
|
||||
}
|
||||
|
||||
public function setTest(Test $test): static
|
||||
{
|
||||
$this->test = $test;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Repository\TestRepository;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
#[ORM\Entity(repositoryClass: TestRepository::class)]
|
||||
class Test
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue]
|
||||
#[ORM\Column]
|
||||
private ?int $id = null;
|
||||
|
||||
#[ORM\Column(length: 60)]
|
||||
private ?string $name = null;
|
||||
|
||||
#[ORM\OneToMany(targetEntity: Question::class, mappedBy: 'test', orphanRemoval: true)]
|
||||
private Collection $questions;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->questions = new ArrayCollection();
|
||||
}
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getName(): ?string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function setName(string $name): static
|
||||
{
|
||||
$this->name = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection<int, Question>
|
||||
*/
|
||||
public function getQuestions(): Collection
|
||||
{
|
||||
return $this->questions;
|
||||
}
|
||||
|
||||
public function addQuestion(Question $question): static
|
||||
{
|
||||
if (!$this->questions->contains($question)) {
|
||||
$this->questions->add($question);
|
||||
$question->setTest($this);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeQuestion(Question $question): static
|
||||
{
|
||||
if ($this->questions->removeElement($question)) {
|
||||
// set the owning side to null (unless already changed)
|
||||
if ($question->getTest() === $this) {
|
||||
$question->setTest(null);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Model\AnswerModel;
|
||||
use App\Repository\UserAnswerRepository;
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
#[ORM\Entity(repositoryClass: UserAnswerRepository::class)]
|
||||
class UserAnswer
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue]
|
||||
#[ORM\Column]
|
||||
private ?int $id = null;
|
||||
|
||||
#[ORM\ManyToOne]
|
||||
#[ORM\JoinColumn(nullable: false)]
|
||||
private ?Question $question = null;
|
||||
|
||||
#[ORM\Column(type: Types::DATETIME_MUTABLE)]
|
||||
private ?\DateTimeInterface $date_created = null;
|
||||
|
||||
#[ORM\Column(type: Types::BOOLEAN)]
|
||||
private bool $is_correct = false;
|
||||
|
||||
#[ORM\Column]
|
||||
private array $answer = [];
|
||||
|
||||
#[ORM\Column(length: 60)]
|
||||
private ?string $uuid;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getQuestion(): ?Question
|
||||
{
|
||||
return $this->question;
|
||||
}
|
||||
|
||||
public function setQuestion(?Question $question): static
|
||||
{
|
||||
$this->question = $question;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDateCreated(): ?\DateTimeInterface
|
||||
{
|
||||
return $this->date_created;
|
||||
}
|
||||
|
||||
public function setDateCreated(\DateTimeInterface $date_created): static
|
||||
{
|
||||
$this->date_created = $date_created;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isCorrect(): bool
|
||||
{
|
||||
return $this->is_correct;
|
||||
}
|
||||
|
||||
public function setIsCorrect(bool $isCorrect): static
|
||||
{
|
||||
$this->is_correct = $isCorrect;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<AnswerModel>
|
||||
*/
|
||||
public function getAnswer(): array
|
||||
{
|
||||
return $this->answer;
|
||||
}
|
||||
|
||||
public function setAnswer(array $answer): static
|
||||
{
|
||||
$this->answer = $answer;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getUuid(): string
|
||||
{
|
||||
return $this->uuid;
|
||||
}
|
||||
|
||||
public function setUuid(string $uuid): static
|
||||
{
|
||||
$this->uuid = $uuid;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace App\Enum;
|
||||
|
||||
enum OperatorsEnum: string
|
||||
{
|
||||
case ADD = '+';
|
||||
case SUB = '-';
|
||||
case MUL = '*';
|
||||
case DIV = '/';
|
||||
case EQL = '=';
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace App\Enum;
|
||||
|
||||
enum QuestionPartTypeEnum: string
|
||||
{
|
||||
case NUMBER = 'number';
|
||||
case OPERATOR = 'op';
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
namespace App\Form\Type;
|
||||
|
||||
use App\Entity\Question;
|
||||
use App\Entity\Test;
|
||||
use App\Entity\UserAnswer;
|
||||
use App\Model\AnswerModel;
|
||||
use App\Model\QuestionModel;
|
||||
use App\Service\QuestionService;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Event\PostSubmitEvent;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\Form\FormEvents;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Validator\Constraints\NotBlank;
|
||||
|
||||
class UserAnswerType extends AbstractType
|
||||
{
|
||||
|
||||
public function __construct(private readonly QuestionService $questionService)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{
|
||||
/** @var QuestionModel $questionModel */
|
||||
$questionModel = $options['questionModel'];
|
||||
$answers = $questionModel->getAnswers();
|
||||
shuffle($answers);
|
||||
$builder
|
||||
->add('answer', ChoiceType::class, [
|
||||
'choices' => $answers,
|
||||
'choice_label' => function (?AnswerModel $answerModel): string {
|
||||
return $answerModel->getName();
|
||||
},
|
||||
'label' => sprintf('Pick up answer(s) for %s', $questionModel->getPrompt()),
|
||||
'required' => true,
|
||||
'multiple' => true,
|
||||
'expanded' => true,
|
||||
'constraints' => [
|
||||
new NotBlank()
|
||||
]
|
||||
])
|
||||
->add('save', SubmitType::class, ['label' => 'Answer'])
|
||||
->addEventListener(FormEvents::POST_SUBMIT, [$this, 'checkAnswer'])
|
||||
;
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver): void
|
||||
{
|
||||
$resolver
|
||||
->setRequired(['test', 'question', 'questionModel'])
|
||||
->setDefaults([
|
||||
'data_class' => UserAnswer::class,
|
||||
])
|
||||
->setAllowedTypes('test', Test::class)
|
||||
->setAllowedTypes('questionModel', QuestionModel::class)
|
||||
->setAllowedTypes('question', Question::class)
|
||||
;
|
||||
}
|
||||
|
||||
public function checkAnswer(PostSubmitEvent $event): void
|
||||
{
|
||||
/** @var UserAnswer $userAnswer */
|
||||
$userAnswer = $event->getData();
|
||||
/** @var Question $question */
|
||||
$question = $event->getForm()->getConfig()->getOption('question');
|
||||
$answer = $userAnswer
|
||||
->setDateCreated(new \DateTime())
|
||||
->setQuestion($question)
|
||||
->getAnswer();
|
||||
|
||||
$userAnswer->setIsCorrect($this->questionService->isValidAnswer($question, $answer));
|
||||
$userAnswer->setAnswer(array_map(fn($a) => $a->getConfig(), $answer));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
|
||||
use Symfony\Component\HttpKernel\Kernel as BaseKernel;
|
||||
|
||||
class Kernel extends BaseKernel
|
||||
{
|
||||
use MicroKernelTrait;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace App\Model;
|
||||
|
||||
final class AnswerModel
|
||||
{
|
||||
public function __construct(
|
||||
private readonly string $name,
|
||||
private readonly string $value,
|
||||
private readonly array $config
|
||||
)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function getValue(): string
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
public function getConfig(): array
|
||||
{
|
||||
return $this->config;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace App\Model;
|
||||
|
||||
final class QuestionModel
|
||||
{
|
||||
public function __construct(
|
||||
private readonly string $prompt,
|
||||
private readonly array $answers
|
||||
)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function getPrompt(): string
|
||||
{
|
||||
return $this->prompt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public function getAnswers(): array
|
||||
{
|
||||
return $this->answers;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace App\Repository;
|
||||
|
||||
use App\Entity\Question;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @extends ServiceEntityRepository<Question>
|
||||
*
|
||||
* @method Question|null find($id, $lockMode = null, $lockVersion = null)
|
||||
* @method Question|null findOneBy(array $criteria, array $orderBy = null)
|
||||
* @method Question[] findAll()
|
||||
* @method Question[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||
*/
|
||||
class QuestionRepository extends ServiceEntityRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, Question::class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace App\Repository;
|
||||
|
||||
use App\Entity\Test;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @extends ServiceEntityRepository<Test>
|
||||
*
|
||||
* @method Test|null find($id, $lockMode = null, $lockVersion = null)
|
||||
* @method Test|null findOneBy(array $criteria, array $orderBy = null)
|
||||
* @method Test[] findAll()
|
||||
* @method Test[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||
*/
|
||||
class TestRepository extends ServiceEntityRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, Test::class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace App\Repository;
|
||||
|
||||
use App\Entity\UserAnswer;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @extends ServiceEntityRepository<UserAnswer>
|
||||
*
|
||||
* @method UserAnswer|null find($id, $lockMode = null, $lockVersion = null)
|
||||
* @method UserAnswer|null findOneBy(array $criteria, array $orderBy = null)
|
||||
* @method UserAnswer[] findAll()
|
||||
* @method UserAnswer[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||
*/
|
||||
class UserAnswerRepository extends ServiceEntityRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, UserAnswer::class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
namespace App\Service;
|
||||
|
||||
use App\Entity\Question;
|
||||
use App\Enum\OperatorsEnum;
|
||||
use App\Enum\QuestionPartTypeEnum;
|
||||
use App\Model\AnswerModel;
|
||||
use App\Model\QuestionModel;
|
||||
|
||||
class QuestionService
|
||||
{
|
||||
public function getQuestionModel(Question $question): QuestionModel
|
||||
{
|
||||
$questionAnswers = $question->getAnswers();
|
||||
$answers = array_map(
|
||||
fn($answer, $i) => new AnswerModel($this->assembleString($answer), $i, $answer),
|
||||
$questionAnswers,
|
||||
array_keys($questionAnswers)
|
||||
);
|
||||
|
||||
return new QuestionModel(
|
||||
$this->assembleString($question->getPrompt(), true),
|
||||
$answers
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Question $question
|
||||
* @param array<AnswerModel> $answer
|
||||
* @return boolean
|
||||
*/
|
||||
public function isValidAnswer(Question $question, array $answer): bool
|
||||
{
|
||||
$prompt = $question->getPrompt();
|
||||
|
||||
$result = $this->calculate($prompt);
|
||||
$answerResults = array_map(fn($a) => $this->calculate($a->getConfig()), $answer);
|
||||
|
||||
foreach($answerResults as $answerResult) {
|
||||
if($answerResult !== $result) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function calculate(array $entries): float
|
||||
{
|
||||
$result = 0;
|
||||
$count = count($entries);
|
||||
$prev = null;
|
||||
|
||||
for($i=0; $i < $count; $i++) {
|
||||
$entry = $entries[$i];
|
||||
$curr = QuestionPartTypeEnum::tryFrom($entry['type']);
|
||||
|
||||
if(!$curr) {
|
||||
throw new \RuntimeException(sprintf('Invalid entry type: %s', $entry['type']));
|
||||
}
|
||||
|
||||
if ($curr === QuestionPartTypeEnum::OPERATOR && $prev !== QuestionPartTypeEnum::NUMBER) {
|
||||
throw new \RuntimeException('Unexpected part, got OPERATOR expected NUMBER');
|
||||
}
|
||||
|
||||
if ($curr === QuestionPartTypeEnum::NUMBER && $prev !== null && $prev !== QuestionPartTypeEnum::OPERATOR) {
|
||||
throw new \RuntimeException('Unexpected part, got NUMBER expected OPERATOR');
|
||||
}
|
||||
|
||||
if ($curr === QuestionPartTypeEnum::NUMBER && $prev === null) {
|
||||
$prev = $curr;
|
||||
$result += (float) $entry['value'];
|
||||
}
|
||||
|
||||
if ($curr === QuestionPartTypeEnum::OPERATOR && $prev === QuestionPartTypeEnum::NUMBER) {
|
||||
$nextEntry = $entries[$i + 1];
|
||||
$next = QuestionPartTypeEnum::tryFrom($nextEntry['type']);
|
||||
if(!$next) {
|
||||
throw new \RuntimeException(sprintf('Invalid entry type: %s', $entry['type']));
|
||||
};
|
||||
|
||||
$curr = OperatorsEnum::tryFrom($entry['value']);
|
||||
switch ($curr) {
|
||||
case OperatorsEnum::ADD:
|
||||
$result += (float) $nextEntry['value'];
|
||||
break;
|
||||
case OperatorsEnum::SUB:
|
||||
$result -= (float) $nextEntry['value'];
|
||||
break;
|
||||
case OperatorsEnum::MUL:
|
||||
$result *= (float) $nextEntry['value'];
|
||||
break;
|
||||
case OperatorsEnum::DIV:
|
||||
if((double) $nextEntry['value'] === 0.0) {
|
||||
throw new \RuntimeException('Division by 0');
|
||||
}
|
||||
$result /= (float) $nextEntry['value'];
|
||||
break;
|
||||
case OperatorsEnum::EQL:
|
||||
throw new \RuntimeException('Unexpected operator');
|
||||
}
|
||||
$prev = $curr;
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function assembleString(array $entries, $isPrompt = false): string
|
||||
{
|
||||
$ret = [];
|
||||
foreach($entries as $entry) {
|
||||
$type = QuestionPartTypeEnum::tryFrom($entry['type']);
|
||||
$ret[] = match($type) {
|
||||
QuestionPartTypeEnum::OPERATOR => OperatorsEnum::tryFrom($entry['value'])->value,
|
||||
QuestionPartTypeEnum::NUMBER => $entry['value'],
|
||||
default => null
|
||||
};
|
||||
}
|
||||
|
||||
if ($isPrompt) {
|
||||
$ret[] = OperatorsEnum::EQL->value;
|
||||
}
|
||||
|
||||
|
||||
return implode(' ', array_filter($ret, fn($r) => $r !== null));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user