<?php
namespace App\Controller\Front\Exercise;
use App\Entity\Exercise\Exercise;
use App\Entity\Exercise\User\ExerciseResult;
use App\Entity\Scholar\Lesson\Lesson;
use App\Entity\Scholar\Module\Module;
use App\Entity\Scholar\Training\Training;
use App\Form\Exercise\User\ExerciseResultType;
use App\Repository\Exercise\User\ExerciseResultRepository;
use App\Service\Exercise\UserExerciseResultManipulator;
use Doctrine\ORM\EntityManagerInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
class AnswerController extends AbstractController
{
public function __construct(
private UserExerciseResultManipulator $manipulator,
private ExerciseResultRepository $exerciseResultRepository,
private EntityManagerInterface $em,
) {}
#[Route(path: '/training/{trainingId}/module/{moduleId}/lesson/{lessonId}/exercise/{id}/{exerciseResultId}', name: 'front_exercise_answer')]
#[ParamConverter('training', options: ['id' => 'trainingId'])]
#[ParamConverter('module', options: ['id' => 'moduleId'])]
#[ParamConverter('lesson', options: ['id' => 'lessonId'])]
#[ParamConverter('exercise', options: ['id' => 'id'])]
#[ParamConverter('exerciseResult', options: ['id' => 'exerciseResultId'])]
public function __invoke(Request $request, Training $training, Module $module, Lesson $lesson, Exercise $exercise, ExerciseResult $exerciseResult): Response
{
if (!$this->isGranted('FRONT_ACCESS', [
'training' => $training,
'module' => $module,
'lesson' => $lesson,
])) {
throw $this->createAccessDeniedException();
}
if (
$exercise->getLesson() !== $lesson
|| $exerciseResult->getExercise() !== $exercise
) {
throw new NotFoundHttpException();
}
if ($this->getUser() === null) {
throw new AccessDeniedException('Access denied.');
}
$exerciseResult = $this->exerciseResultRepository->findOneBy(
[
'id' => $exerciseResult->getId(),
'exercise' => $exercise->getId(),
'user' => $this->getUser(),
'finishedAt' => null,
],
[
'startedAt' => 'DESC',
]
);
if (null === $exerciseResult) {
return $this->redirectToRoute('front_channel_exercise_show', [
'lessonId' => $lesson->getId(),
'exerciseId' => $exercise->getId(),
'moduleId' => $module->getId(),
'trainingId' => $training->getId(),
]);
}
// Populate the questions.
$this->manipulator->populate($exercise, $exerciseResult);
$form = $this->createForm(ExerciseResultType::class, $exerciseResult);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->manipulator->finish($exercise, $exerciseResult);
// Check if the current Exercise submission is not an error (start the exercise in less then 3s ago).
if (3 > $exerciseResult->getTime()) {
$this->em->remove($exerciseResult);
$this->em->flush();
return $this->redirectToRoute('front_channel_lesson_show', [
'trainingId' => $training->getId(),
'moduleId' => $module->getId(),
'lessonId' => $lesson->getId(),
], 303);
}
$this->em->persist($exerciseResult);
$this->em->persist($exercise);
$this->em->flush();
return $this->redirectToRoute('front_exercise_solution', [
'trainingId' => $training->getId(),
'moduleId' => $module->getId(),
'lessonId' => $lesson->getId(),
'id' => $exercise->getId(),
'resultId' => $exerciseResult->getId(),
]);
}
return $this->render('Front/Exercise/answer.html.twig', [
'channel' => $training->getOwnerChannel(),
'training' => $training->getId(),
'module' => $module->getId(),
'exercise' => $exercise,
'exercise_result' => $exerciseResult,
'form' => $form->createView(),
'lesson' => $lesson,
'count_form_errors' => $form->getErrors(true)->count()
]);
}
}