<?php
namespace App\Controller;
use App\Dto\SpeakerSearchDto;
use App\Entity\Category;
use App\Entity\PromoCode;
use App\Entity\Speaker;
use App\Entity\SpeakerConsultation;
use App\Entity\SpeakerCourse;
use App\Form\RequestConsultationType;
use App\Form\SpeakerOrderType;
use App\Service\CartService;
use App\Service\DiscountService;
use App\Service\Email;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Contracts\Translation\TranslatorInterface;
use Twig\Error\LoaderError;
use Twig\Error\RuntimeError;
use Twig\Error\SyntaxError;
use Twig\Extra\Intl\IntlExtension;
use App\Repository\ReviewRepository;
use App\Dto\Cabinet\ReviewSearchDto;
class SpeakerController extends AbstractController
{
private TranslatorInterface $translator;
public function __construct(TranslatorInterface $translator)
{
$this->translator = $translator;
}
/**
* @Route("/speakers/", name="speaker.list")
*/
public function index(): Response
{
return $this->render('speaker/index.html.twig', [
'categories' => $this->getDoctrine()->getRepository(Category::class)->findBy([], ['name' => 'asc']),
]);
}
/**
* @Route("/speakers/searh.json", name="speaker.search.json")
* @param Request $request
* @return JsonResponse
*/
public function search(Request $request): JsonResponse
{
$searchDto = new SpeakerSearchDto((string)$request->get('search'));
if ($request->get('category')) {
$searchDto->setCategory($this->getDoctrine()->getRepository(Category::class)->find((int)$request->get('category')));
}
if ($request->get('page')) {
$searchDto->setPage((int)$request->get('page'));
}
if ($request->get('order_by')) {
$searchDto->setOrderBy($request->get('order_by'));
}
$speakerRep = $this->getDoctrine()->getRepository(Speaker::class);
return $this->json([
'data' => $this->renderView('speaker/search.html.twig', [
'speakers' => $speakerRep->search($searchDto),
]),
'left' => $speakerRep->searchCount($searchDto) - $searchDto->getPage() * $searchDto->getPerPage(),
]);
}
/**
* @Route("/{uri}", name="speaker.detail", requirements={"uri"=".*"}, priority=-100)
* @param $uri
* @param Request $request
* @return Response
*/
public function detail($uri, Request $request, CartService $cartService, ReviewRepository $reviewRepository): Response
{
$speaker = $this->getDoctrine()->getRepository(Speaker::class)->findOneBy([
'uri' => $uri,
'enabled' => true,
'status' => Speaker::STATUS_APPROVE
]);
if (!$speaker) {
throw $this->createNotFoundException();
}
$promoCodes = $cartService->getPromoCodes();
$dto = new ReviewSearchDto();
$dto->setSortBy('date')->setOrderBy('desc');
$reviews = $reviewRepository->findBySpeaker($speaker, $dto);
return $this->render('speaker/detail.html.twig', [
'speaker' => $speaker,
'reviews' => $reviews,
'category' => $this->getDoctrine()->getRepository(Category::class)->find((int)$request->get('category')),
'orderForm' => $this->createForm(SpeakerOrderType::class)->createView(),
'promoVal' => isset($promoCodes[$speaker->getId()])
? $this->getDoctrine()->getRepository(PromoCode::class)->find($promoCodes[$speaker->getId()])
: '',
'courses' => $this->getDoctrine()->getRepository(SpeakerCourse::class)->findBy(['enabled' => true, 'speaker' => $speaker]),
]);
}
/**
* @Route("/speakers/subscribe/{speaker}", name="speaker.subscribe")
* @param Speaker $speaker
* @return JsonResponse
*/
public function subscribe(Speaker $speaker): JsonResponse
{
$res = [
'success' => false,
];
if (!is_null($this->getUser())) {
$speaker->addSubscriber($this->getUser());
$em = $this->getDoctrine()->getManager();
$em->persist($speaker);
$em->flush();
$res['success'] = true;
$res['message'] = $this->translator->trans('message.subscribed_to_speaker');
}
return $this->json($res);
}
/**
* @Route("/speakers/timeslots/{speaker}/{fromDate}/{toDate}", name="speaker.timeslots")
* @param Speaker $speaker
* @param $fromDate
* @param $toDate
* @param Request $request
* @return JsonResponse
* @throws \Exception
*/
public function timeslots(Speaker $speaker, $fromDate, $toDate, Request $request, CartService $cartService): JsonResponse
{
try {
$timezone = new \DateTimeZone($request->get('timezone'));
$utcTimezone = new \DateTimeZone('UTC');
} catch (\Exception $e) {
return $this->json([]);
}
$fromDateUTC = (new \DateTime($fromDate, $timezone))->setTimezone($utcTimezone);
$toDateUTC = (new \DateTime($toDate, $timezone))->setTimezone($utcTimezone);
$cartService->setTimeZone($timezone->getName());
$now = (new \DateTime())->setTimezone($timezone);
$data = [];
foreach ($this->getDoctrine()
->getRepository(SpeakerConsultation::class)
->findSpeakerSlots($speaker, $fromDateUTC, $toDateUTC) as $v) {
if ($v['status'] == SpeakerConsultation::STATUS_CANCELED) {
continue;
}
if ($v['startDate'] < $now) {
continue;
}
$data[] = [
'id' => $v['id'],
'date' => $v['startDate']->setTimezone($timezone)->format('Y-m-d'),
'label' => $v['startDate']->setTimezone($timezone)->format('H:i') . ' - ' . $v['endDate']->setTimezone($timezone)->format('H:i'),
'freeze' => ((empty($v['order_type']) || !empty($v['order_refunded'])) && (is_null($v['freezeDate']) || $v['freezeDate'] < (new \DateTime()))) ? 0 : 1,
];
}
return $this->json($data);
}
/**
* @Route("/speakers/timeslot/{consultation}", name="speaker.timeslot")
* @param SpeakerConsultation $consultation
* @return JsonResponse
*/
public function timeslot(SpeakerConsultation $consultation, DiscountService $discount, CartService $cartService): JsonResponse
{
$promoCodes = $cartService->getPromoCodes();
if (!empty($promoCodes[$consultation->getSpeaker()->getId()])) {
$discount->setPromoCode($this->getDoctrine()
->getRepository(PromoCode::class)
->find($promoCodes[$consultation->getSpeaker()->getId()])
);
}
$price = $consultation->getPrice();
$groupPrice = $consultation->getGroupPrice();
$priceTotal = $discount->getConsultationPrice($consultation);
$groupPriceTotal = $discount->getConsultationGroupPrice($consultation);
$intl = $this->container->get('twig')->getExtension(IntlExtension::class);
$formatCurrency = function ($price) use ($intl) {
return $intl->formatCurrency($price / 100, 'RUB', ['fraction_digit' => 0]);
};
return $this->json([
'price' => $formatCurrency($price),
'groupPrice' => $formatCurrency($groupPrice),
'priceTotal' => $formatCurrency($priceTotal),
'groupPriceTotal' => $formatCurrency($groupPriceTotal),
'priceDiscount' => $formatCurrency($price - $priceTotal),
'groupPriceDiscount' => $formatCurrency($groupPrice - $groupPriceTotal),
'discountDesc' => $discount->getInfo(),
]);
}
/**
* @Route("/speakers/{uri}/request-consultation", name="speaker.request-consultation"), requirements={"uri"=".*"}, priority=-100)
* @param $uri
* @param Request $request
* @param Email $email
* @param MailerInterface $mailer
* @return Response
* @throws TransportExceptionInterface
* @throws LoaderError
* @throws RuntimeError
* @throws SyntaxError
*/
public function requestConsultation($uri, Request $request, Email $email, MailerInterface $mailer): Response
{
$speaker = $this->getDoctrine()->getRepository(Speaker::class)->findOneBy([
'uri' => $uri,
'enabled' => true,
'status' => Speaker::STATUS_APPROVE
]);
$speakerName = "{$speaker->getFirstName()} {$speaker->getLastName()}";
$form = $this->createForm(RequestConsultationType::class, null, [
'speaker_name' => $speakerName
]);
$form->handleRequest($request);
if ($form->isSubmitted() and $form->isValid()) {
$message = $email->create('request_consultation', [
'name' => strip_tags($form->get('name')->getData()),
'email' => strip_tags($form->get('email')->getData()),
'description' => strip_tags($form->get('description')->getData()),
])->to($this->getParameter('manager_email'));
$mailer->send($message);
return $this->redirectToRoute('speaker.detail', [
'uri' => $uri
]);
}
return $this->render('speaker/request-consultation.twig', [
'form' => $form->createView(),
'speaker_name' => $speakerName
]);
}
}