<?php
namespace App\EventSubscriber\TimeSlot;
use ApiPlatform\Core\EventListener\EventPriorities;
use App\Entity\App\Role;
use App\Entity\App\TimeSlot\TimeSlot;
use App\Entity\App\User;
use App\Entity\App\Vendor;
use App\Error\ErrorDataContainerForExceptions;
use App\Exception\AccessDeniedException;
use App\Exception\NotFoundException;
use App\Repository\App\TimeSlot\TimeSlotItemRepository;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\ViewEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
class TimeSlotPreWriteSuscriber implements EventSubscriberInterface
{
private $translator;
private $tokenStorage;
private $timeSlotItemRepository;
private $request;
public function __construct (TranslatorInterface $translator, TokenStorageInterface $tokenStorage, TimeSlotItemRepository $timeSlotItemRepository)
{
$this->translator = $translator;
$this->tokenStorage = $tokenStorage;
$this->timeSlotItemRepository = $timeSlotItemRepository;
}
/**
* @param ViewEvent $
* @throws \Exception
*/
public function onKernelView( ViewEvent $event){
$timeSlot = $event->getControllerResult();
$this->request = $event->getRequest();
$method = $this->request->getMethod();
if(!($timeSlot instanceof TimeSlot)
|| $method !== Request::METHOD_PUT && $method !== Request::METHOD_POST){
return;
}
//Comprobamos si el usuario está logeado
$userCurrent = $this->tokenStorage->getToken()->getUser();
if($userCurrent === "anon."){
throw new AccessDeniedException(
$this->translator->trans('user no logged')
);
}
//Comprobamos que el usuario exista y no esté eliminado (softDelete)
if(!($userCurrent instanceof User))
throw new NotFoundException($this->translator->trans('User current not found'));
//Comprobamos que timeSlot pertenece al vendor del usuario logeado
$vendor=$userCurrent->getVendorStaff()[0]->getVendor();
if(!($vendor instanceof Vendor) || $vendor->getId() !== $timeSlot->getVendor()->getId()){
throw new AccessDeniedException(
$this->translator->trans('vendor no found')
);
}
//Comprobamos el rol del usuario para determinar si tiene permiso
try {
$role = $userCurrent->getVendorStaff()[0]->getRoleStaff()[0]->getRole()->getName();
}catch (\Exception $ex){
$role="";
}
if(!in_array($role, [Role::ROLE_ADMIN])){
throw new AccessDeniedException(
$this->translator->trans('access_allowed_only_for') . $role
);
}
//Comprobamos los solapamiento horarios
$this->timeCollection($timeSlot->getTimeSlotItems()->getValues());
//Actualizamos la fecha de actualización de la franja horaria
$timeSlot->setUpdatedAt(new \DateTime("now"));
}
/**
* Creamos la estructura de tiempos por días de la semana
* @param array $itemSlotItems
* @return void
* @throws \Exception
*/
private function timeCollection(Array $itemSlotItems=[]){
$daysWithConflict="";
$times=[];
$lang=null;
//Obtenemos el idioma de la request
$headerLangs = $this->request->headers->get("accept-language");
if(!empty($headerLangs)){
$lang = explode(",",$headerLangs)[0];
}
foreach ($itemSlotItems as $itemSlotItem){
foreach ($itemSlotItem->getDaysOfWeek() as $dayOfWeek) {
$startTime = $itemSlotItem->getStartTime();
$endTime = $itemSlotItem->getEndTime();
if($startTime && $endTime && $startTime>$endTime) {
$itemSlotItem->setStartTime($endTime);
$itemSlotItem->setEndTime($startTime);
}
$times[$dayOfWeek]["startTime"][] = $itemSlotItem->getStartTime();
$times[$dayOfWeek]["endTime"][] = $itemSlotItem->getEndTime();
}
}
//Buscamos solapamientos horarios por día
foreach ($times as $idx=>$dayOfWeek){
$startTime = $dayOfWeek["startTime"];
$currentPos=0;
while((count($startTime) -1) >$currentPos){
if(!$this->testTimeRange($dayOfWeek, $currentPos)){
$daysWithConflict .= $this->translator->trans("daysOfWeek." . $idx, [], 'messages', $lang) . " TimeSlotPreWriteSuscriber.php";
$startTime=[];
}
$currentPos++;
}
}
if(strlen($daysWithConflict)>0){
$errorText = $this->translator->trans("timeSlot.timeOverlap",[],'messages',$lang);
throw new \Exception(
new ErrorDataContainerForExceptions(array("message"=>$errorText.$daysWithConflict,"code"=>100)), 417
);
}
}
/**
* Comprobamos si solapamos los tiempos
* @param $itemCollection
* @param int $currentPos
* @return bool
*/
private function testTimeRange($itemCollection, $currentPos=0)
{
for ($i = $currentPos + 1 ; $i < count($itemCollection["startTime"]); $i++) {
if ($itemCollection["startTime"][$currentPos] < $itemCollection["endTime"][$i]
&& $itemCollection["startTime"][$i] < $itemCollection["endTime"][$currentPos])
return false;
}
return true;
}
public static function getSubscribedEvents ():array
{
return [
KernelEvents::VIEW => ['onKernelView', EventPriorities::PRE_WRITE]
];
}
}