<?php
namespace App\Controller;
use App\Entity\Alumno;
use App\Entity\SolicitudBecaAlumno;
use App\Entity\TestEvaluacionAlumno;
use App\Exception\CustomException;
use App\Form\FrontSolicitudBecaAlumnoType;
use App\Form\FrontTestEvaluacionAlumnoType;
use App\Security\AlumnoVoter;
use App\Security\CursoVoter;
use App\Service\AlumnoService;
use App\Service\CursoService;
use App\Service\SolicitudService;
use Mpdf\Output\Destination;
use Symfony\Component\HttpFoundation\RedirectResponse;
use DateTimeInterface;
use App\Entity\Curso;
use App\Entity\EstadoSolicitud;
use App\Entity\GrupoEdadUsuario;
use App\Entity\Localidad;
use App\Entity\Solicitud;
use App\Entity\Usuario;
use App\Form\FrontFormBusquedaCursoType;
use App\Form\FrontSolicitudType;
use App\Service\Globales;
use DateTime;
use Doctrine\ORM\EntityManagerInterface;
use Exception;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
#[Route(path: '/cursos')]
class FrontCursoController extends AbstractController
{
public function __construct(
private readonly EntityManagerInterface $em,
private readonly Globales $globales,
private readonly SolicitudService $solicitudService,
private readonly AlumnoService $alumnoService,
private readonly CursoService $cursoService)
{
}
#[Route(path: '/ver/{curso}-{slug}', name: 'front_ver_curso', methods: 'GET|POST')]
#[ParamConverter('curso', options: ['mapping' => ['curso' => 'id']])]
public function ver(Curso $curso, string $slug): RedirectResponse|Response
{
// Redirigir si el slug no coincide con el actual (SEO)
if ($slug !== $curso->getSlug()) {
return $this->redirectToRoute('front_ver_curso', [
'curso' => $curso->getId(),
'slug' => $curso->getSlug()
], Response::HTTP_MOVED_PERMANENTLY);
}
// Obtiene y comprueba que el curso cumpla unos criterios. Ver repo.
$curso = $this->em->getRepository(Curso::class)->comprobarAccesibilidadCurso($curso);
if (!$curso) {
return $this->redirectToRoute('front_inicio');
}
// Comprueba si $now esta dentro de las fechas de inicio y fin de solicitud de inscripción del curso.
$fechasEnPlazo = $curso->estaInscripcionAbierta();
// Comprueba si el usuario está inscrito en otro curso y su estado como alumno es != BAJA.
$estaMatriculadoEnOtroCursoNoBaja = $this->isGranted('IS_AUTHENTICATED') && $this->em->getRepository(Alumno::class)->estaMatriculadoEnOtroCursoNoBaja($this->getUser());
return $this->render('front-cursos/ver.html.twig', [
'curso' => $curso,
'fechasEnPlazo' => $fechasEnPlazo,
'estaMatriculadoEnOtroCursoNoBaja' => $estaMatriculadoEnOtroCursoNoBaja
]);
}
/**
*
* @throws Exception
*/
#[Security("is_granted('IS_AUTHENTICATED')")]
#[Route(path: '/solicitar-inscripcion/{curso}/{solicitud}', name: 'front_solicitar_inscripcion_curso', methods: 'GET|POST')]
#[ParamConverter('curso', options: ['mapping' => ['curso' => 'id']])]
#[ParamConverter('solicitud', options: ['mapping' => ['solicitud' => 'id']])]
public function solicitarInscripcionCurso(Request $request, Curso $curso, Solicitud $solicitud = null): Response
{
$this->denyAccessUnlessGranted(CursoVoter::PUEDE_INSCRIBIRSE, $curso);
/** @var Usuario $usuario */
$usuario = $this->getUser();
// Comprueba si $now esta dentro de las fechas de inicio y fin de solicitud de inscripción del curso.
$fechasEnPlazo = $curso->estaInscripcionAbierta();
// Comprueba si el usuario está inscrito en otro curso y su estado como alumno es != BAJA.
$estaMatriculadoEnOtroCursoNoBaja = $this->em->getRepository(Alumno::class)->estaMatriculadoEnOtroCursoNoBaja($this->getUser());
if (!$fechasEnPlazo) {
$this->addFlash('error', 'No está dentro del plazo para poder realizar la solicitud.');
return $this->redirectToRoute('front_ver_curso', [
'curso' => $curso->getId(),
'slug' => $curso->getSlug()
]);
}
if ($estaMatriculadoEnOtroCursoNoBaja) {
$this->addFlash('error', 'Ya está matriculado y no puede realizar otra solicitud.');
return $this->redirectToRoute('front_ver_curso', [
'curso' => $curso->getId(),
'slug' => $curso->getSlug()
]);
}
// Si la solicitud existe y está en estado diferente a borrador, mostramos error.
$solicitudExistente = $this->globales->comprobarSolicitudCursoUsuario($curso, $usuario);
if ($solicitudExistente) {
// Si está en borrador...
if ($solicitudExistente->getEstado()->getId() === 4) {
$solicitud = $solicitudExistente;
} else { // En cualquier otro estado, que muestre error.
$this->addFlash('error', 'Ya ha realizado una solicitud de inscripcion en este curso.');
return $this->redirectToRoute('front_ver_curso', [
'curso' => $curso->getId(),
'slug' => $curso->getSlug()
]);
}
}
if (!$solicitud instanceof Solicitud) {
$estadoSolicitudBorrador = $this->em->getRepository(EstadoSolicitud::class)->find(4);
$solicitud = new Solicitud();
$solicitud
->setEstado($estadoSolicitudBorrador)
->setCurso($curso)
->setUsuario($usuario)
->setNombre($usuario->getNombre())
->setApellidos($usuario->getApellidos())
->setDniNie($usuario->getDniNie())
->setDireccion($usuario->getDireccion())
->setLocalidad($usuario->getLocalidad())
->setCodigoPostal($usuario->getCodigoPostal())
->setEmail($usuario->getEmail())
->setTelefono1($usuario->getTelefono1())
->setTelefono2($usuario->getTelefono2())
->setFechaNacimiento($usuario->getFechaNacimiento())
->setSexo($usuario->getSexo());
$this->em->persist($solicitud);
}
$form = $this->createForm(FrontSolicitudType::class, $solicitud);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
try {
// Si pulsamos el botón de guardar y finalizar, se cambia el estado a pendiente.
$btnSubmitPulsado = $form->getClickedButton()->getConfig()->getName();
// Calculamos el grupo de edad al que pertenece el usuario.
if ($solicitud->getFechaNacimiento() instanceof DateTimeInterface) {
$aniosUsuario = $solicitud->getFechaNacimiento()->diff(new DateTime())->y;
$solicitud->setEdadSolicitud($aniosUsuario);
$gruposEdadesUsuario = $this->em->getRepository(GrupoEdadUsuario::class)->findAll();
$grupoEdadEncontrado = null;
foreach ($gruposEdadesUsuario as $ge) {
if ($aniosUsuario >= $ge->getMin() && $aniosUsuario <= $ge->getMax()) {
$grupoEdadEncontrado = $ge;
break;
}
}
$solicitud->setGrupoEdad($grupoEdadEncontrado);
}
if ($btnSubmitPulsado === 'guardarBorrador') {
$this->em->flush();
$this->addFlash('success', 'Solicitud guardada como borrador.');
}
// Si pulsamos el botón de guardar y finalizar, lo mandamos a la vista detalle del curso.
if ($btnSubmitPulsado === 'guardarFinalizar') {
// Ponemos la solicitud como pendiente de revisión.
$estadoSolicitudPendiente = $this->em->getRepository(EstadoSolicitud::class)->find(1);
$solicitud->setEstado($estadoSolicitudPendiente);
// Añadimos y evaluamos los criterios.
$this->solicitudService->evaluarCriterios($solicitud);
$this->em->flush();
// Generamos el word
$this->solicitudService->generarWordAnexos($solicitud, true);
return $this->render('front-cursos/solicitud-realizada.html.twig', ['solicitud' => $solicitud]);
}
return $this->redirectToRoute('front_solicitar_inscripcion_curso', [
'curso' => $curso->getId(),
'solicitud' => $solicitud->getId()
]);
} catch (Exception $e) {
$this->addFlash('error', 'Se ha producido un error.');
}
}
return $this->render('front-cursos/solicitar-inscripcion.html.twig', [
'curso' => $curso,
'solicitud' => $solicitud,
'form' => $form->createView()
]);
}
#[Route(path: '', name: 'front_listado_cursos', options: ['expose' => true], methods: 'GET|POST')]
#[Route(path: '/{slugLocalidad}', name: 'front_listado_cursos_localidad', options: ['expose' => true], methods: 'GET|POST')]
#[ParamConverter('slugLocalidad', options: ['mapping' => ['slugLocalidad' => 'slug']])]
public function listado(Request $request, Localidad $slugLocalidad = null): Response
{
$ordenarPor = 'destacados';
$nombre = '';
$itemsPorPagina = 30;
$pagina = $request->query->getInt('page', 1);
if ($request->query->get('itemsPorPagina') && trim($request->query->get('itemsPorPagina')) !== '') {
$itemsPorPagina = $request->query->get('itemsPorPagina');
}
$localidad = null;
if ($slugLocalidad instanceof Localidad) {
$localidad = $slugLocalidad->getSlug();
}
// FORM BÚSQUEDA
$frontFormBusquedaCursos = $this->createForm(FrontFormBusquedaCursoType::class, [
'localidad' => $slugLocalidad
]);
$frontFormBusquedaCursos->handleRequest($request);
if ($frontFormBusquedaCursos->isSubmitted() && $frontFormBusquedaCursos->isValid()) {
$nombre = $frontFormBusquedaCursos->get('nombre')->getData() ?? '';
}
// FIN FORM BÚSQUEDA
$cursos = $this->em->getRepository(Curso::class)->obtenerBuscadorFront($nombre, $localidad, $pagina, $itemsPorPagina, null, $ordenarPor);
return $this->render('front-cursos/listado.html.twig', [
'cursos' => $cursos,
'itemsPorPagina' => $itemsPorPagina,
'frontFormBusquedaCursos' => $frontFormBusquedaCursos->createView(),
'localidad' => $slugLocalidad,
]);
}
/**
* @throws CustomException
*/
#[Security("is_granted('IS_AUTHENTICATED')")]
#[Route(path: '/descargar-anexo-1/{solicitud}', name: 'front_descargar_anexo_1', methods: 'GET')]
public function descargarAnexo1(Solicitud $solicitud): Response
{
return $this->solicitudService->descargarSolicitudPdfAnexo1($solicitud);
}
/**
* @throws CustomException
*/
#[Security("is_granted('IS_AUTHENTICATED')")]
#[Route(path: '/descargar-anexo-2/{solicitud}', name: 'front_descargar_anexo_2', methods: 'GET')]
public function descargarAnexo2(Solicitud $solicitud): Response
{
return $this->solicitudService->descargarSolicitudPdfAnexo2($solicitud);
}
/**
* @throws CustomException
*/
#[Security("is_granted('IS_AUTHENTICATED')")]
#[Route(path: '/descargar-anexo-3/{solicitud}', name: 'front_descargar_anexo_3', methods: 'GET')]
public function descargarAnexo3(Solicitud $solicitud): Response
{
return $this->solicitudService->descargarSolicitudPdfAnexo3($solicitud);
}
/**
*
* @throws Exception
*/
#[Security("is_granted('IS_AUTHENTICATED')")]
#[Route(path: '/test-evaluacion/{alumno}', name: 'front_test_evaluacion_alumno', methods: 'GET|POST')]
public function testEvaluacionAlumno(Request $request, Alumno $alumno): Response
{
$this->denyAccessUnlessGranted(AlumnoVoter::PUEDE_HACER_TEST_EVALUACION, $alumno);
$testEvaluacionAlumno = new TestEvaluacionAlumno();
$testEvaluacionAlumno->setAlumno($alumno);
$this->em->persist($testEvaluacionAlumno);
$form = $this->createForm(FrontTestEvaluacionAlumnoType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
try {
$testEvaluacionAlumno->setRespuestas($form->getData());
$this->em->flush();
$this->addFlash('success', 'Operación realizada correctamente.');
return $this->redirectToRoute('front_solicitudes_perfil');
} catch (Exception $e) {
$this->addFlash('error', 'Se ha producido un error.');
}
}
return $this->render('front-cursos/test-evaluacion-alumno.html.twig', [
'testEvaluacionAlumno' => $testEvaluacionAlumno,
'form' => $form->createView()
]);
}
/**
*
* @throws Exception
*/
#[Security("is_granted('IS_AUTHENTICATED')")]
#[Route(path: '/solicitar-beca/{alumno}', name: 'front_solicitar_beca_alumno', methods: 'GET|POST')]
public function solicitarBecaAlumno(Request $request, Alumno $alumno): Response
{
$this->denyAccessUnlessGranted(AlumnoVoter::PUEDE_SOLICITAR_BECA, $alumno);
$solicitudBecaAlumno = new SolicitudBecaAlumno();
$solicitudBecaAlumno->setAlumno($alumno);
$this->em->persist($solicitudBecaAlumno);
$form = $this->createForm(FrontSolicitudBecaAlumnoType::class, $solicitudBecaAlumno);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
try {
$this->em->flush();
// Generamos y enviamos los ficheros correspondientes.
$this->alumnoService->generarFicherosSolicitudBeca($solicitudBecaAlumno, true);
$this->addFlash('success', 'Operación realizada correctamente.');
return $this->redirectToRoute('front_solicitudes_perfil');
} catch (Exception $e) {
$this->addFlash('error', 'Se ha producido un error.');
}
}
return $this->render('front-cursos/solicitar-beca-alumno.html.twig', [
'solicitudBecaAlumno' => $solicitudBecaAlumno,
'form' => $form->createView()
]);
}
/**
* @throws Exception
*/
#[Route(path: '/descargar-info-curso/{curso}', name: 'front_descargar_info_curso', methods: 'GET')]
public function descargarInfoCurso(Curso $curso): void
{
$this->cursoService->generarPdfInfoCurso($curso, Destination::INLINE);
}
}