<?php
namespace App\Controller;
use App\Entity\Event;
use App\Entity\EventRegistration;
use App\Entity\SatisfactionClientAnswer;
use App\Entity\SatisfactionClientSurvey;
use App\Entity\SatisfactionClientSurveyResponse;
use App\Repository\AccountingFirmRepository;
use App\Repository\AuthorizedDomainRepository;
use App\Repository\CollaboratorRepository;
use App\Repository\EventRepository;
use App\Repository\SatisfactionClientQuestionRepository;
use App\Repository\SatisfactionClientSurveyRepository;
use App\Repository\SatisfactionClientSurveyResponseRepository;
use App\Services\WidgetMailing;
use Doctrine\ORM\EntityManagerInterface;
use Qferrer\Mjml\Twig\MjmlExtension;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mime\Email;
use Symfony\Component\Routing\Annotation\Route;
use Twig\Environment;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
use Symfony\Component\HttpFoundation\Response;
class WidgetSatisfactionClientController extends AbstractController
{
protected MjmlExtension $mjmlRenderer;
protected Environment $twig;
private MailerInterface $mailer;
public function __construct(MailerInterface $mailer, MjmlExtension $mjmlRenderer, Environment $twig)
{
$this->mailer = $mailer;
$this->mjmlRenderer = $mjmlRenderer;
$this->twig = $twig;
}
#[Route('/check-satisfaction-client', name: 'w_satsifaction_client_check')]
public function ctrl_checkSatisfactionClient(Request $request, AccountingFirmRepository $repository, string $prefix = null): JsonResponse
{
$token = $request->query->get('token');
$host = $request->get('host');
if ($token && $host) {
$accountingFirm = $repository->findOneBy(['satisfactionToken' => $token]);
$isAuthorized = false;
if ($accountingFirm && in_array($host, $accountingFirm->getListAuthorizedDomains())) {
$isAuthorized = true;
}
$url = $isAuthorized ? $accountingFirm->getSatisfactionWidgetUrl() : null;
} else {
$accountingFirm = $repository->findOneBy(['host' => $host]);
$url = $accountingFirm ? $prefix . $this->generateUrl('w_satisfaction_client_get') : null;
}
return $this->json($url);
}
#[Route('/widget-satisfaction-client', name: 'w_satisfaction_client_get')]
public function ctrl_widgetSatisfactionClient(
Request $request,
AccountingFirmRepository $repository,
AuthorizedDomainRepository $domains,
SatisfactionClientSurveyRepository $surveyRepository,
SatisfactionClientSurveyResponseRepository $responseRepository,
CollaboratorRepository $collaboratorRepository,
ParameterBagInterface $params
) {
$token = $request->query->get('token');
$host = $request->get('host');
$surveyId = $request->query->get('surveyId');
$tokenClient = $request->query->get('tokenClient');
$tokenCollaborators = $request->query->get('tokenCollaborators');
$collaboratorTokens = $tokenCollaborators === "preview"
? ["preview"]
: explode(',', $tokenCollaborators);
if ($host != "preview") {
$accountingFirm = $repository->findOneBy(['host' => $host]);
if (is_null($accountingFirm)) {
$domains = $domains->findBy(['name' => $host]);
if (empty($domains)) {
throw new NotFoundHttpException('Domaine non autorisé');
}
foreach ($domains as $dom) {
$tmp_ac = $dom->getAccountingFirm();
if ($tmp_ac->getSatisfactionToken() == $token) {
$accountingFirm = $tmp_ac;
break;
}
}
}
if (is_null($accountingFirm)) {
throw new NotFoundHttpException('Cabinet non trouvé');
}
}
$survey = $surveyRepository->find($surveyId);
if (!$survey || $survey->getAccountingFirm()->getId() !== $accountingFirm->getId()) {
throw new NotFoundHttpException('Enquête non trouvé');
}
if($collaboratorTokens[0] != "preview") {
foreach ($collaboratorTokens as $tokenCollaborator) {
$collaborator = $collaboratorRepository->findOneBy(['token' => $tokenCollaborator]);
if (!$collaborator || !$survey->getCollaborators()->contains($collaborator)) {
throw new NotFoundHttpException('Collaborateur non autorisé');
}
}
}
if($tokenClient != "preview" && $collaboratorTokens[0] != "preview") {
foreach ($collaboratorTokens as $tokenCollaborator) {
$existingResponse = $responseRepository->findBySurveyAndTokens($survey, $tokenClient, $tokenCollaborator);
if ($existingResponse) {
return $this->render('widget_satisfaction_client/already_responded.twig', [
'accountingFirm' => $accountingFirm
]);
}
}
}
if($tokenClient != "preview" && $collaboratorTokens[0] != "preview") {
return $this->render('widget_satisfaction_client/content.html.twig', [
'accountingFirm' => $accountingFirm,
'survey' => $survey,
'tokenClient' => $tokenClient,
'tokenCollaborators' => $collaboratorTokens,
'serverUrl' => $params->get('domain_widget_satisfaction_client'),
'domainWidget' => $_ENV['DOMAIN_WIDGET_SATISFACTION_CLIENT'],
]);
} else {
return $this->render('widget_satisfaction_client/preview.html.twig', [
'accountingFirm' => $accountingFirm,
'survey' => $survey,
'tokenClient' => $tokenClient,
'tokenCollaborators' => $collaboratorTokens,
'serverUrl' => $params->get('domain_widget_satisfaction_client'),
'domainWidget' => $_ENV['DOMAIN_WIDGET_SATISFACTION_CLIENT'],
]);
}
}
#[Route('/submit', name: 'w_submit_satisfaction_survey', methods: ['POST'])]
public function submit(
Request $request,
SatisfactionClientSurveyRepository $surveyRepository,
SatisfactionClientQuestionRepository $questionRepository,
EntityManagerInterface $em,
SatisfactionClientSurveyResponseRepository $responseRepository
): JsonResponse {
try {
$data = json_decode($request->getContent(), true);
if (!$data) {
return new JsonResponse(['error' => 'Invalid JSON data'], Response::HTTP_BAD_REQUEST);
}
$requiredFields = ['surveyId', 'tokenClient', 'tokenCollaborators', 'answers'];
foreach ($requiredFields as $field) {
if (!isset($data[$field])) {
return new JsonResponse(['error' => "Missing required field: $field"], Response::HTTP_BAD_REQUEST);
}
}
$survey = $surveyRepository->find($data['surveyId']);
if (!$survey) {
return new JsonResponse(['error' => 'Survey not found'], Response::HTTP_NOT_FOUND);
}
$collaboratorTokens = is_array($data['tokenCollaborators'])
? $data['tokenCollaborators']
: array_filter(explode(',', $data['tokenCollaborators']));
foreach ($collaboratorTokens as $tokenCollaborator) {
$existingResponse = $responseRepository->findBySurveyAndTokens($survey, $data['tokenClient'], $tokenCollaborator);
if ($existingResponse) {
return new JsonResponse(
['error' => 'You have already responded to this survey for collaborator: ' . $tokenCollaborator],
Response::HTTP_CONFLICT
);
}
}
foreach ($collaboratorTokens as $tokenCollaborator) {
$surveyResponse = new SatisfactionClientSurveyResponse();
$surveyResponse->setSurvey($survey);
$surveyResponse->setAnsweredAt(new \DateTime());
foreach ($data['answers'] as $answerData) {
if (!isset($answerData['questionId'])) {
continue;
}
$question = $questionRepository->find($answerData['questionId']);
if (!$question || $question->getSurvey()->getId() !== $survey->getId()) {
continue;
}
$answer = new SatisfactionClientAnswer();
$answer->setQuestion($question);
$answer->setSurveyResponse($surveyResponse);
$answer->setTokenClient($data['tokenClient']);
$answer->setTokenCollaborator($tokenCollaborator);
if (isset($answerData['rating']) && $answerData['rating'] !== null) {
$answer->setRating((int)$answerData['rating']);
}
if (isset($answerData['textAnswer'])) {
$answer->setTextAnswer($answerData['textAnswer']);
} elseif ($question->isMandatoryFreeText()) {
return new JsonResponse(
['error' => 'Text answer is required for question: ' . $question->getId()],
Response::HTTP_BAD_REQUEST
);
}
$em->persist($answer);
$surveyResponse->addAnswer($answer);
}
$em->persist($surveyResponse);
}
$em->flush();
return new JsonResponse([
'success' => true,
'message' => 'Survey responses saved successfully for all collaborators',
'responsesCount' => count($surveyResponse->getAnswers())
]);
} catch (\Exception $e) {
return new JsonResponse([
'error' => 'An error occurred while saving responses',
'details' => $e->getMessage()
], Response::HTTP_INTERNAL_SERVER_ERROR);
}
}
//récupère le js qui intègre le widget
#[Route('/embed', name: 'w_satisfaction_client_embed')]
public function embed()
{
$root = $this->getParameter('kernel.project_dir');
$path = $root . '/public/widgets/widget_satisfaction_client/widget_satisfaction_client.js';
return new BinaryFileResponse($path);
}
#[Route('/{filename}.{format}', name: 'w_event_files')]
public function widget_files(string $filename, string $format)
{
$allowed = array('png', 'jpg', 'jpeg', 'gif', 'js', 'svg', 'eot', 'ttf', 'woff');
if (in_array($format, $allowed)) {
$root = $this->getParameter('kernel.project_dir');
$path = $root . '/public/widget_event/' . $filename . '.' . $format;
return new BinaryFileResponse($path);
}
return false;
}
//récupérer image, fichier,... (on verra plus tard ça)
#[Route('/cover-file/{id}', name: 'w_satisfaction_client_files_cover')]
public function widget_files_vich(Event $event, KernelInterface $kernel)
{
$filename = $event->getCoverImage();
if (!$filename) {
throw $this->createNotFoundException("Aucun fichier associé à cet événement.");
}
// Exemple avec VichUploaderBundle qui stocke dans public/uploads/event_covers/
$filePath = $kernel->getProjectDir() . '/upload/events/' . $filename;
if (!file_exists($filePath)) {
throw $this->createNotFoundException("Le fichier n'existe pas.");
}
return (new BinaryFileResponse($filePath))
->setContentDisposition(ResponseHeaderBag::DISPOSITION_INLINE, $filename);
}
#[Route('/widget-satisfaction-client-send-form', name: 'widget_satisfaction_client_send_form', methods: ['POST', 'OPTIONS'])]
public function sendForm(
Request $request,
EntityManagerInterface $em,
AccountingFirmRepository $repository,
SatisfactionClientSurveyRepository $surveyRepository,
SatisfactionClientQuestionRepository $questionRepository
): JsonResponse {
$data = json_decode($request->getContent(), true);
if (json_last_error() !== JSON_ERROR_NONE) {
return new JsonResponse(['message' => 'Invalid JSON'], JsonResponse::HTTP_BAD_REQUEST);
}
$accountingFirm = $repository->findOneById($data['cabinetId'] ?? null);
if (!$accountingFirm) {
return new JsonResponse(['message' => 'Cabinet introuvable'], JsonResponse::HTTP_NOT_FOUND);
}
$survey = $surveyRepository->findByAccountingFirm($accountingFirm);
if (!$survey) {
return new JsonResponse(['message' => 'Aucune enquête satisfaction active trouvée'], JsonResponse::HTTP_NOT_FOUND);
}
if (!isset($data['answers']) || !is_array($data['answers'])) {
return new JsonResponse(['message' => 'Aucune réponse transmise'], JsonResponse::HTTP_BAD_REQUEST);
}
$surveyResponse = new SatisfactionClientSurveyResponse();
$surveyResponse->setSurvey($survey);
foreach ($data['answers'] as $answerData) {
if (!isset($answerData['questionId'])) {
continue;
}
$question = $questionRepository->find($answerData['questionId']);
if (!$question || $question->getSurvey()->getId() !== $survey->getId()) {
continue;
}
$answer = new SatisfactionClientAnswer();
$answer->setQuestion($question)
->setSurveyResponse($surveyResponse);
if ($question->isMandatoryFreeText()) {
$answer->setTextAnswer($answerData['textAnswer'] ?? '');
} else {
$rating = $answerData['rating'] ?? null;
if ($rating >= 1 && $rating <= 5) {
$answer->setRating($rating);
}
}
$surveyResponse->addAnswer($answer);
}
$em->persist($surveyResponse);
$em->flush();
return new JsonResponse([
'message' => "Merci pour votre participation. Vos retours sont précieux et seront attentivement étudiés par notre équipe."
], JsonResponse::HTTP_OK);
}
}