src/Controller/VoteController.php line 370

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use App\Entity\Action;
  4. use App\Entity\User;
  5. use App\Entity\Vendor;
  6. use App\Entity\VoteEvent;
  7. use App\Entity\VoteItem;
  8. use App\Enumerations\ActionEnumeration;
  9. use App\Enumerations\TableTypeEnumeration;
  10. use App\Enumerations\VendorStatusEnumeration;
  11. use App\Enumerations\VoteEventStatusEnumeration;
  12. use App\Exceptions\BadFormDataException;
  13. use App\Exceptions\MultipleVotesRunningException;
  14. use App\Exceptions\VoteException;
  15. use App\Form\ApproveVendorType;
  16. use App\Form\CreateVoteType;
  17. use App\Form\ScrubVoteType;
  18. use App\Form\VoteVendorType;
  19. use Doctrine\Common\Collections\ArrayCollection;
  20. use Doctrine\Common\Collections\Criteria;
  21. use Doctrine\ORM\EntityManagerInterface;
  22. use Doctrine\Persistence\ManagerRegistry;
  23. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  24. use Symfony\Component\HttpFoundation\RedirectResponse;
  25. use Symfony\Component\HttpFoundation\Request;
  26. use Symfony\Component\HttpFoundation\Response;
  27. use Symfony\Component\HttpFoundation\Session\Session;
  28. use Symfony\Component\Routing\Annotation\Route;
  29. class VoteController extends AbstractController
  30. {
  31.     #[Route('/vote/create''app_createvoteevent')]
  32.     public function createVote(Request $requestEntityManagerInterface $entityManager)
  33.     {
  34.         $this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY');
  35.         $this->denyAccessUnlessGranted('ROLE_CREATEVOTE');
  36.         /**
  37.          * @var User $user
  38.          */
  39.         $user $this->getUser();
  40.         $voteEvent = new VoteEvent();
  41.         $form $this->createForm(CreateVoteType::class, $voteEvent);
  42.         $form->handleRequest($request);
  43.         try {
  44.             if ($form->isSubmitted() && $form->isValid()) {
  45.                 $voteEvent
  46.                     ->setCreatedBy($user)
  47.                     ->setStatus(VoteEventStatusEnumeration::STATUS_RUNNING);
  48.                 /** @noinspection SqlNoDataSourceInspection */
  49.                 /** @noinspection SqlResolve */
  50.                 $checkVotes $entityManager
  51.                     ->getConnection()
  52.                     ->prepare("SELECT * from vote_event ve where ve.ends_on > :start AND ve.vote_complete = 'false'")
  53.                     ->executeQuery([':start' => $voteEvent->getStartsOn()->format("Y-m-d H:i:s")])
  54.                     ->fetchAllAssociative();
  55.                 if (!empty($checkVotes)) {
  56.                     $this->addFlash("flash_error""This voting event starts before other events have ended.  Please select a start date after the last vote ends.");
  57.                     throw new BadFormDataException("Bad form data");
  58.                 }
  59.                 $entityManager->persist($voteEvent);
  60.                 new Action($userActionEnumeration::ACTION_VOTE"New Vote Event has been created."$entityManager);
  61.                 $entityManager->flush();
  62.                 return new RedirectResponse("/vote/list");
  63.             }
  64.         } catch (BadFormDataException) {
  65.         } //
  66.         return $this->render("vote/createvote.html.twig", [
  67.             'createvoteForm' => $form->createView(),
  68.             'user' => [
  69.                 'name' => $user->getName(),
  70.                 'roles' => $user->getRoles()
  71.             ]
  72.         ]);
  73.     }
  74.     #[Route('/vote/list''app_listvoteevents')]
  75.     public function listVoteEvents(EntityManagerInterface $entityManager)
  76.     {
  77.         $this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY');
  78.         $criteria = new Criteria();
  79.         $criteria->where(Criteria::expr()->neq('status'VoteEventStatusEnumeration::STATUS_DELETED));
  80.         $events $entityManager->getRepository(VoteEvent::class)->matching($criteria);
  81.         /**
  82.          * @var VoteEvent $e
  83.          */
  84.         foreach ($events as &$e) {
  85.             $e->calculations $this->getVoteTotals($entityManager$e);
  86.             $e->isRunning $this->voteIsActive($e);
  87.             $e->isEnded $this->voteIsEnded($e);
  88.             $e->canProcess $e->getStatus() === VoteEventStatusEnumeration::STATUS_PROCESSING;
  89.             if($e->isRunning) {
  90.                 $staff $entityManager->getRepository(User::class)->findAll();
  91.                 $staffMax $e->getStaffVotes();
  92.                 /**
  93.                  * @var User $s
  94.                  */
  95.                 $staffVotes = [];
  96.                 foreach ($staff as &$s) {
  97.                     $ve $s->getVoteItems();
  98.                     $svote 0;
  99.                     /**
  100.                      * @var VoteItem $sitem
  101.                      */
  102.                     foreach ($ve as $sitem) {
  103.                         if ($sitem->getVoteEvent()->getId() === $e->getId()) {
  104.                             $svote += $sitem->getVotes();
  105.                         }
  106.                     }
  107.                     $staffVotes[] = ['name' => $s->getName(), 'votes' => $svote'max' => $staffMax];
  108.                 }
  109.                 usort($staffVotes, function($a$b){
  110.                    return strcmp($a['name'], $b['name']);
  111.                 });
  112.                 $e->staffVotes $staffVotes;
  113.             }
  114.         }
  115.         /**
  116.          * @var User $user
  117.          */
  118.         $user $this->getUser();
  119.         return $this->render('vote/listvote.html.twig', [
  120.             'user' => [
  121.                 'name' => $user->getName(),
  122.                 'roles' => $user->getRoles()
  123.             ],
  124.             'events' => $events
  125.         ]);
  126.     }
  127.     #[Route('/vote/start''app_startvoteevent')]
  128.     public function startVote(EntityManagerInterface $entityManagerRequest $request)
  129.     {
  130.         $voteID $request->query->get('voteevent');
  131.         /**
  132.          * @var VoteEvent $event
  133.          */
  134.         $event $entityManager->getRepository(VoteEvent::class)->find($voteID);
  135.         $now = new \DateTime();
  136.         $event->setStartsOn($now)->setStatus(VoteEventStatusEnumeration::STATUS_RUNNING);
  137.         $entityManager->persist($event);
  138.         $entityManager->flush();
  139.         return new RedirectResponse("/vote/list");
  140.     }
  141.     #[Route('/vote/end''app_endvoteevent')]
  142.     public function endVote(EntityManagerInterface $entityManagerRequest $request$status VoteEventStatusEnumeration::STATUS_PROCESSING)
  143.     {
  144.         $voteID $request->query->get('voteevent');
  145.         /**
  146.          * @var VoteEvent $event
  147.          */
  148.         $event $entityManager->getRepository(VoteEvent::class)->find($voteID);
  149.         $now = new \DateTime();
  150.         $event->setEndsOn($now)->setVoteComplete(true)->setStatus($status);
  151.         $entityManager->persist($event);
  152.         $entityManager->flush();
  153.         return new RedirectResponse("/vote/list");
  154.     }
  155.     #[Route('/vote/process''app_processvendorvotes')]
  156.     public function approveVote(EntityManagerInterface $entityManagerRequest $request)
  157.     {
  158.         $vendors $entityManager->getRepository(Vendor::class)->findAll();
  159.         $voteEventID $request->query->get('voteevent');
  160.         $approved 0;
  161.         $tablespaces 0;
  162.         $smbooths 0;
  163.         $lgbooths 0;
  164.         $tbooths 0;
  165.         $bodega 0;
  166.         $mature 0;
  167.         $islands 0;
  168.         /**
  169.          * @var Vendor $vendor
  170.          */
  171.         foreach ($vendors as $vendor) {
  172.             if ($vendor->getStatus() === VendorStatusEnumeration::STATUS_APPROVED) {
  173.                 $approved++;
  174.                 $table $vendor->getTableScore();
  175.                 switch ($table) {
  176.                     case TableTypeEnumeration::TABLESIZE_SMALLBOOTH:
  177.                         $smbooths++;
  178.                         break;
  179.                     case TableTypeEnumeration::TABLESIZE_LARGEBOOTH:
  180.                         $lgbooths++;
  181.                         break;
  182.                     case TableTypeEnumeration::TABLESIZE_TATTOO:
  183.                         $tbooths++;
  184.                         break;
  185.                     case TableTypeEnumeration::TABLESIZE_HALF:
  186.                         $bodega++;
  187.                         break;
  188.                     case TableTypeEnumeration::TABLESIZE_ISLAND:
  189.                         $islands++;
  190.                     default:
  191.                         $tablespaces += (int)$table;
  192.                         break;
  193.                 }
  194.             }
  195.         }
  196.         $criteria = new Criteria();
  197.         $criteria->where(Criteria::expr()->neq('status'VendorStatusEnumeration::STATUS_APPROVED));
  198.         $vendors $entityManager->getRepository(Vendor::class)->matching($criteria)->toArray();
  199.         $form $this->createForm(ApproveVendorType::class, ['voteevent' => $voteEventID'approved' => $approved'score' => 0]);
  200.         $form->handleRequest($request);
  201.         try {
  202.             if ($form->isSubmitted() && $form->isValid()) {
  203.                 $minScore = (int)$form->get('score')->getData();
  204.                 if ($minScore === 0) {
  205.                     $this->addFlash("flash_error""You have selected no threshold, this will result in all vendors being approved.");
  206.                     throw new BadFormDataException("Nope");
  207.                 }
  208.                 /**
  209.                  * @var Vendor $vendor
  210.                  */
  211.                 foreach($vendors as $vendor) {
  212.                     $vendScore $vendor->calculateEventScore($voteEventID)->getEventScore();
  213.                     if ($vendScore >= $minScore) {
  214.                         $vendor->setStatus(VendorStatusEnumeration::STATUS_APPROVED);
  215.                         $entityManager->persist($vendor);
  216.                     }
  217.                 }
  218.                 /**
  219.                  * @var VoteEvent $voteEvent
  220.                  */
  221.                 $voteEvent $entityManager->getRepository(VoteEvent::class)->find($voteEventID);
  222.                 $voteEvent->setStatus(VoteEventStatusEnumeration::STATUS_COMPLETE);
  223.                 $entityManager->flush();
  224.                 return new RedirectResponse("/vote/list");
  225.             }
  226.         } catch (BadFormDataException) {
  227.         }
  228.         $voteEvent $entityManager->getRepository(VoteEvent::class)->find($voteEventID);
  229.         /**
  230.          * @var Vendor $v
  231.          */
  232.         foreach ($vendors as &$v) {
  233.             // This restricts vote items down to a single event
  234.             $v->calculateEventScore($voteEventID);
  235. //            $items = $v->getVoteEventItems($voteEventID);
  236. //            $v->setVoteItems($items);
  237.         }
  238.         usort($vendors, function ($a$b){
  239.             /**
  240.              * @var Vendor $a
  241.              * @var Vendor $b
  242.              */
  243.             $isEq $a->getEventScore() === $b->getEventScore();
  244.             if ($isEq) {
  245.                 return $a->getName() >= $b->getName();
  246.             }
  247.             return $a->getEventScore() <= $b->getEventScore();
  248.         });
  249.         /**
  250.          * @var User $user
  251.          */
  252.         $user $this->getUser();
  253.         return $this->render('vote/processvote.html.twig', [
  254.             'user' => [
  255.                 'name' => $user->getName(),
  256.                 'roles' => $user->getRoles()
  257.             ],
  258.             'vendors' => $vendors,
  259.             'event' => $voteEvent,
  260.             'preapproved' => $approved,
  261.             'tables' => $tablespaces,
  262.             'lgbooth' => $lgbooths,
  263.             'smbooth' => $smbooths,
  264.             'tbooth' => $tbooths,
  265.             'bodega' => $bodega,
  266.             'islands' => $islands,
  267.             'approveform' => $form->createView()
  268.         ]);
  269.     }
  270.     #[Route('/vote/delete'name"app_scrubvoteevent")]
  271.     public function scrubvoteevent(Request $requestEntityManagerInterface $entityManagerManagerRegistry $doctrine): Response
  272.     {
  273.         $this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY');
  274.         $this->denyAccessUnlessGranted('ROLE_EDITSTAFF');
  275.         $this->denyAccessUnlessGranted('ROLE_EDITVENDOR');
  276.         /**
  277.          * @var User $user
  278.          */
  279.         $user $this->getUser();
  280.         $voteeventID $request->query->get('voteevent');
  281.         $voteevent $entityManager->getRepository(VoteEvent::class)->find($voteeventID);
  282.         $form $this->createForm(ScrubVoteType::class, $voteevent);
  283.         $form->handleRequest($request);
  284.         if ($form->isSubmitted() && $form->isValid()) {
  285.             new Action($userActionEnumeration::ACTION_VOTE"Vote event {$voteeventID} has been deleted."$entityManager);
  286.             $connection $entityManager->getConnection();
  287.             $sql "DELETE FROM vote_item WHERE vote_event_id = :vid";
  288.             $statement $connection->prepare($sql);
  289.             $statement->executeQuery([":vid" => $voteeventID]);
  290.             $sql "DELETE FROM vote_event WHERE id = :vid";
  291.             $statement $connection->prepare($sql);
  292.             $statement->executeQuery([":vid" => $voteeventID]);
  293.             $entityManager->flush();
  294.             return $this->redirectToRoute('app_dashboard');
  295.         }
  296.         return $this->render('vote/scrubvoteevent.html.twig', [
  297.             'scrubvoteForm' => $form->createView(),
  298.             'user' => [
  299.                 'email' => $user->getEmail(),
  300.                 'name' => $user->getName(),
  301.                 'roles' => $user->getRoles(),
  302.             ],
  303.             'voteEvent' => $voteevent
  304.         ]);
  305.     }
  306.     #[Route('/vote/cancel''app_cancelvoteevent')]
  307.     public function cancelVote(EntityManagerInterface $entityManagerRequest $request)
  308.     {
  309.         return $this->endVote($entityManager$requestVoteEventStatusEnumeration::STATUS_CANCELLED);
  310.     }
  311.     #[Route('/vote/{voteid?}/{vendorid?}''app_staffvote')]
  312.     public function vote(EntityManagerInterface $entityManagerRequest $requestSession $session, ?int $voteid, ?int $vendorid)
  313.     {
  314.         $this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY');
  315.         /**
  316.          * @var User $user
  317.          */
  318.         $user $this->getUser();
  319.         /**
  320.          * @var VoteEvent $voteEvent
  321.          */
  322.         $voteEvents $this->getRunningVoteEvent($entityManager$voteid);
  323.         if (empty($voteEvents) && !empty($voteid)){
  324.             $session->getFlashBag()->add("flash_error""Could not find that voting round");
  325.             return new RedirectResponse("/");
  326.         } elseif (empty($voteEvents)) {
  327.             $session->getFlashBag()->add("flash_error""Vote Machine is not running");
  328.             return new RedirectResponse("/");
  329.         }
  330.         if (count($voteEvents) === 1) {
  331.             /**
  332.              * @var VoteEvent $voteEvent
  333.              */
  334.             $voteEvent array_pop($voteEvents);
  335.             $items $this->getVoteItems($entityManager$user$voteEvent);
  336.             if (empty($vendorid)) {
  337.                 return $this->render("vote/startvote.html.twig", [
  338.                     'user' => [
  339.                         'name' => $user->getName(),
  340.                         'roles' => $user->getRoles()
  341.                     ],
  342.                     'items' => $items,
  343.                     'event' => $voteEvent
  344.                 ]);
  345.             }
  346.             $vendor $entityManager->getRepository(Vendor::class)->find($vendorid);
  347.             $voteItem $entityManager->getRepository(VoteItem::class)->findOneBy([
  348.                 'User' => $user,
  349.                 'Vendor' => $vendor,
  350.                 'VoteEvent' => $voteEvent
  351.             ]);
  352.             if (empty($voteItem)) {
  353.                 $voteItem = new VoteItem();
  354.                 $voteItem->setVoteEvent($voteEvent)->setVendor($vendor)->setUser($user);
  355.             }
  356.             $voteItem->setIsSkip(false)->setMaxVotes($voteEvent->getMaxVendorVotes());
  357.             $form $this->createForm(VoteVendorType::class, $voteItem);
  358.             $form->handleRequest($request);
  359.             try {
  360.                 if ($form->isSubmitted() && $form->isValid()) {
  361.                     $entityManager->persist($voteItem);
  362.                     $entityManager->flush();
  363.                     $nextVend $this->getPrevNextVendor($entityManager$vendor$voteEvent,1);
  364.                     return new RedirectResponse("/vote/{$voteEvent->getId()}/{$nextVend}");
  365.                 }
  366.             } catch (BadFormDataException) {
  367.             }
  368.             $itemVotes 0;
  369.             /**
  370.              * @var VoteItem $item
  371.              */
  372.             foreach ($items as $item) {
  373.                 $v $item->getVotes();
  374.                 $v = !empty($v) ? (int)$v 0;
  375.                 $itemVotes += $v;
  376.             }
  377.             $remainingVotes = (int)$voteEvent->getStaffVotes() - $itemVotes;
  378.             return $this->render("vote/vote.html.twig", [
  379.                 'user' => [
  380.                     'name' => $user->getName(),
  381.                     'roles' => $user->getRoles()
  382.                 ],
  383.                 'event' => $voteEvent,
  384.                 'items' => $items,
  385.                 'voteItem' => $voteItem,
  386.                 'remainingVotes' => $remainingVotes,
  387.                 'voteForm' => $form->createView(),
  388.                 'prevID' => $this->getPrevNextVendor($entityManager$vendor$voteEvent, -1),
  389.                 'nextID' => $this->getPrevNextVendor($entityManager$vendor$voteEvent1)
  390.             ]);
  391.         } else {
  392.             return $this->render("vote/activeevents.html.twig", [
  393.                 'user' => [
  394.                     'name' => $user->getName(),
  395.                     'roles' => $user->getRoles()
  396.                 ],
  397.                 'events' => $voteEvents
  398.             ]);
  399.         }
  400.     }
  401.     private function getVoteItems(EntityManagerInterface $entityManagerUser $userVoteEvent $voteEvent)
  402.     {
  403.         $allItems $user->getVoteItems();
  404.         $voteEventId $voteEvent->getId();
  405.         $category $voteEvent->getTableCategory();
  406.         $tempItems = [];
  407.         $voteItems = [];
  408.         /**
  409.          * @var VoteItem $item
  410.          */
  411.         foreach ($allItems as $item) {
  412.             if ($item->getVoteEvent()->getId() !== $voteEventId) {
  413.                 continue;
  414.             }
  415.             $tempItems[] = $item;
  416.         }
  417.         $criteria = new Criteria();
  418.         $criteria->where(Criteria::expr()->neq('status'VendorStatusEnumeration::STATUS_APPROVED));
  419.         $vendors $entityManager->getRepository(Vendor::class)->matching($criteria);
  420.         /**
  421.          * @var Vendor $vendor
  422.          */
  423.         foreach ($vendors as $vendor) {
  424.             if ($vendor->getTableCategory() !== $category) {
  425.                 continue;
  426.             }
  427.             $vendorSeen false;
  428.             /**
  429.              * @var VoteItem $item
  430.              */
  431.             foreach ($tempItems as $item) {
  432.                 if ($item->getVendor()->getId() === $vendor->getId()) {
  433.                     $voteItems[] = $item;
  434.                     $vendorSeen true;
  435.                     break;
  436.                 }
  437.             }
  438.             if (!$vendorSeen) {
  439.                 $newItem = new VoteItem();
  440.                 $newItem->setVoteEvent($voteEvent)->setVendor($vendor)->setUser($user);
  441.                 $voteItems[] = $newItem;
  442.             }
  443.         }
  444.         return $voteItems;
  445.     }
  446.     private function voteIsEnded(VoteEvent $event)
  447.     {
  448.         $now = new \DateTime();
  449.         $end $event->getEndsOn();
  450.         if ($end === null) {
  451.             return false;
  452.         }
  453.         $isEnded = ($now->diff($endfalse))->invert;
  454.         return $isEnded === 1;
  455.     }
  456.     private function voteIsActive(VoteEvent $event)
  457.     {
  458.         $status $event->getStatus();
  459.         return $status === VoteEventStatusEnumeration::STATUS_RUNNING;
  460.     }
  461.     private function getVoteTotals(EntityManagerInterface $entityManagerVoteEvent $event)
  462.     {
  463.         $users $entityManager->getRepository(User::class)->findAll();
  464.         $totalVotes count($users) * $event->getStaffVotes();
  465.         $currentVotes 0;
  466.         $items $event->getVoteItems();
  467.         /**
  468.          * @var VoteItem $i
  469.          */
  470.         foreach ($items as $i) {
  471.             $currentVotes += $i->getVotes();
  472.         }
  473.         $percentComplete = ($currentVotes $totalVotes) * 100;
  474.         return ([
  475.             'total' => $totalVotes,
  476.             'current' => $currentVotes,
  477.             'percent' => $percentComplete
  478.         ]);
  479.     }
  480.     private function getRunningVoteEvent(EntityManagerInterface $entityManager, ?int $voteid): array
  481.     {
  482.         $events $entityManager->getRepository(VoteEvent::class)->findAll();
  483.         if (!empty($voteid)) {
  484.             $events = [$entityManager->getRepository(VoteEvent::class)->find($voteid)];
  485.         }
  486.         $active = [];
  487.         /**
  488.          * @var VoteEvent $e
  489.          */
  490.         foreach ($events as &$e) {
  491.             if ($this->voteIsActive($e)) {
  492.                 $e->calculations $this->getVoteTotals($entityManager$e);
  493.                 $active[] = $e;
  494.             }
  495.         }
  496.         return $active;
  497.     }
  498.     private function getPrevNextVendor(EntityManagerInterface $entityManagerVendor $vendorVoteEvent $voteEventint $offset 0): int|null
  499.     {
  500.         if ($offset === 0) {
  501.             return $vendor->getId();
  502.         }
  503.         $gtlt $offset ">" "<";
  504.         $asde $offset "ASC" "DESC";
  505.         $doctrine $entityManager->getConnection();
  506.         $sql "SELECT v.id FROM vendor v WHERE v.id {$gtlt} :vid and v.status != :app and v.table_category = :tcat ORDER BY v.id {$asde} LIMIT 1";
  507.         $query $doctrine->prepare($sql)->executeQuery([':vid' => $vendor->getId(), ':app' => VendorStatusEnumeration::STATUS_APPROVED':tcat' => $voteEvent->getTableCategory() ]);
  508.         $vid $query->fetchOne();
  509.         /**
  510.          * @var Vendor $newVend
  511.          */
  512.         $newVend $entityManager->getRepository(Vendor::class)->find($vid);
  513.         if (empty($newVend)) {
  514.             return null;
  515.         }
  516.         return $newVend->getId();
  517.     }
  518. }