src/Controller/Rest/CartRestController.php line 354

Open in your IDE?
  1. <?php
  2. namespace App\Controller\Rest;
  3. use App\Entity\Course;
  4. use App\Entity\CartItem;
  5. use App\Entity\CourseData;
  6. use App\Service\CartService;
  7. use Doctrine\DBAL\Connection;
  8. use Swagger\Annotations as SWG;
  9. use App\Entity\CourseOccurrence;
  10. use App\Repository\PersonRepository;
  11. use App\Repository\CartItemRepository;
  12. use App\Service\ConfigurationService;
  13. use FOS\RestBundle\Request\ParamFetcher;
  14. use App\Repository\CourseFieldRepository;
  15. use App\Repository\CourseDataRepository;
  16. use Doctrine\Persistence\ManagerRegistry;
  17. use Nelmio\ApiDocBundle\Annotation\Model;
  18. use App\Repository\OAuth\ClientRepository;
  19. use Symfony\Component\HttpFoundation\Request;
  20. use Symfony\Component\Security\Core\Security;
  21. use App\Repository\CourseOccurrenceRepository;
  22. use App\Repository\OAuth\AccessTokenRepository;
  23. use FOS\RestBundle\Controller\Annotations\View;
  24. use Symfony\Component\Routing\Annotation\Route;
  25. use App\Repository\CourseOccurrenceTimeRepository;
  26. use FOS\RestBundle\Controller\Annotations\QueryParam;
  27. use App\Controller\Traits\SingleOccurrenceRequestValidatable;
  28. use League\Bundle\OAuth2ServerBundle\Manager\AccessTokenManagerInterface;
  29. /**
  30.  * @Route("/rest/cart")
  31.  */
  32. class CartRestController extends AbstractRestCartableController
  33. {
  34.     use SingleOccurrenceRequestValidatable;
  35.     private $courseOccurrenceRepo;
  36.     protected $managerRegistry;
  37.     public function __construct(
  38.         ClientRepository $clientRepository,
  39.         AccessTokenManagerInterface $accessTokenManagerInterface,
  40.         AccessTokenRepository $accessTokenRepository,
  41.         Security $security,
  42.         CartService $cartService,
  43.         PersonRepository $personRepo,
  44.         CourseOccurrenceRepository $courseOccurrenceRepo,
  45.         ManagerRegistry $managerRegistry
  46.     ) {
  47.         parent::__construct($clientRepository$accessTokenManagerInterface$accessTokenRepository$security$managerRegistry$cartService$personRepo);
  48.         $this->courseOccurrenceRepo $courseOccurrenceRepo;
  49.         $this->managerRegistry $managerRegistry;
  50.     }
  51.     /**
  52.      * @Route("/add", name="rest_cart_add", methods="PUT")
  53.      * @SWG\Put(
  54.      *     produces={"application/json"},
  55.      *     consumes={"application/x-www-form-urlencoded"}
  56.      * )
  57.      * @SWG\Parameter(name="courseOccurrence", in="body", required=true, schema=@SWG\Schema(type="integer"))
  58.      * @SWG\Parameter(name="quantity", in="body", required=true, schema=@SWG\Schema(type="integer"))
  59.      * @SWG\Parameter(name="courseOccurrenceTime", in="body", required=false, schema=@SWG\Schema(type="integer"))
  60.      * @SWG\Response(
  61.      *     response=200,
  62.      *     description="Returns json containing a confirmation message",
  63.      *     @SWG\Schema(
  64.      *         type="object",
  65.      *         @SWG\Property(property="success", type="boolean", description="Flag if request was successful"),
  66.      *         @SWG\Property(property="message", type="string", description="Response message."),
  67.      *     )
  68.      * )
  69.      * @SWG\Response(
  70.      *     response=400,
  71.      *     description="Returned if request parameter were invalid."
  72.      * )
  73.      * @SWG\Response(
  74.      *     response=403,
  75.      *     description="Returned if access to course occurrence was denied."
  76.      * )
  77.      * @SWG\Response(
  78.      *     response=404,
  79.      *     description="Returned if course occurrence was not found."
  80.      * )
  81.      * @SWG\Tag(name="rest")
  82.      * @View(serializerGroups={"public"})
  83.      */
  84.     public function add(
  85.         Request $request
  86.         CourseOccurrenceTimeRepository $courseOccurrenceTimeRepository
  87.     )
  88.     {
  89.         $courseOccurrenceId $request->get('courseOccurrence');
  90.         $quantity $request->get('quantity');
  91.         if (empty($quantity)) {
  92.             throw new \Exception(sprintf('Der Parameter „%s“ fehlt leider.''quantity'));
  93.         }
  94.         $violation $this->validateSingleOccurrenceRequest($courseOccurrenceId$quantity);
  95.         if ($violation !== null) {
  96.             return $violation;
  97.         }
  98.         $courseOccurrence $this->getCourseOccurrence($courseOccurrenceId);
  99.         $courseOccurrenceTimeId null;
  100.         // Validate course template availability
  101.         if ($courseOccurrence->getCourse()->getCourseNature() == 'CourseTemplate') {
  102.             // Obtain course occurrence time id
  103.             $courseOccurrenceTimeId $request->get('courseOccurrenceTime');
  104.             if (empty($courseOccurrenceTimeId)) {
  105.                 throw new \Exception(sprintf('Der Parameter „%s“ fehlt leider.''courseOccurrenceTime'));
  106.             }
  107.             // Fetch time
  108.             $courseOccurrenceTime $courseOccurrenceTimeRepository->find($courseOccurrenceTimeId);
  109.             if ($courseOccurrenceTime === null) {
  110.                 throw $this->createNotFoundException('Der angegebene Zeit-Slot konnte nicht gefunden werden.');
  111.             }
  112.             if ($courseOccurrenceTime->getAvailability() == 'NotAvailable') {
  113.                 throw new \Exception(sprintf('Time is not available.'));
  114.             }
  115.             // Todo check collision with booked courses
  116.         } else {
  117.             $courseOccurrenceTime null;
  118.             if (!$courseOccurrence->isAvailable()) {
  119.                 throw $this->createNotFoundException('Dieser Kurs kann nicht in den Warenkorb gelegt werden.');
  120.             }
  121.         }
  122.         $em $this->managerRegistry->getManager();
  123.         $cart $this->getCart();
  124.         if (!$cart->getId()) {
  125.             $em->flush();
  126.         }
  127.         $cartItem $this->cartService->getCartItemIfExists($courseOccurrence$cartfalse$courseOccurrenceTimeId);
  128.         if ($cartItem) {
  129.             if ($courseOccurrence->getCourse()->getCourseNature() != 'CourseTemplate') {
  130.                 $cartItem->increaseQuantity($quantity);
  131.                 foreach ($cartItem->getMaterialCosts() as $materialCost) {
  132.                     $materialCost->increaseQuantity($quantity);
  133.                 }
  134.             }
  135.         } else {
  136.             $cartItem CartItem::createWithCart($cart$courseOccurrence$quantity$courseOccurrenceTime);
  137.             $em->persist($cartItem);
  138.             if ($courseOccurrence->getMaterialCost() > 0) {
  139.                 $materialCost CartItem::createWithCartItem($cartItem);
  140.                 $em->persist($materialCost);
  141.             }
  142.         }
  143.         $em->flush();
  144.         return [
  145.             'success' => true,
  146.             'message' => $quantity . ($quantity ' Kurse' ' Kurs') . ' in den Warenkorb gelegt.',
  147.         ];
  148.     }
  149.     /**
  150.      * @Route("/set-quantity", name="rest_cart_set-quantity", methods="PUT")
  151.      * @SWG\Put(
  152.      *     produces={"application/json"},
  153.      *     consumes={"application/x-www-form-urlencoded"}
  154.      * )
  155.      * @SWG\Parameter(name="courseOccurrence", in="body", required=true, schema=@SWG\Schema(type="integer"))
  156.      * @SWG\Parameter(name="quantity", in="body", required=true, schema=@SWG\Schema(type="integer"))
  157.      * @SWG\Response(
  158.      *     response=200,
  159.      *     description="Returns json containing a confirmation message"
  160.      * )
  161.      * @SWG\Response(
  162.      *     response=400,
  163.      *     description="Returned if request parameter were invalid."
  164.      * )
  165.      * @SWG\Response(
  166.      *     response=403,
  167.      *     description="Returned if access to course occurrence was denied."
  168.      * )
  169.      * @SWG\Response(
  170.      *     response=404,
  171.      *     description="Returned if course occurrence was not found."
  172.      * )
  173.      * @SWG\Tag(name="rest")
  174.      * @View(serializerGroups={"public"})
  175.      */
  176.     public function setQuantity(Request $request)
  177.     {
  178.         $courseOccurrenceId $request->get('courseOccurrence');
  179.         $quantity $request->get('quantity');
  180.         $violation $this->validateSingleOccurrenceRequest($courseOccurrenceId$quantity);
  181.         if ($violation !== null) {
  182.             return $this->json($violation400);
  183.         }
  184.         $courseOccurrence $this->getCourseOccurrence($courseOccurrenceId);
  185.         $cart $this->getCart();
  186.         $cartItem $this->cartService->getCartItemIfExists($courseOccurrence$cart);
  187.         if (!$cartItem) {
  188.             throw $this->createNotFoundException('The requested item is not in current cart.');
  189.         }
  190.         $message '';
  191.         if ($quantity $courseOccurrence->getFreeSlots()) {
  192.             if (!$courseOccurrence->getReservationAllowed()) {
  193.                 return [
  194.                     'success' => false,
  195.                     'message' => 'Es sind keine freien Plätze mehr verfügbar.',
  196.                 ];
  197.             }
  198.             $message 'Menge im Warenkorb aktualisiert. Es sind nicht mehr genug Plätze verfügbar. Ihre Anmeldung wird auf die Warteliste gestellt.';
  199.         }
  200.         $cartItem->setQuantity($quantity);
  201.         if ($cartItem->getMaterialCosts()) {
  202.             foreach ($cartItem->getMaterialCosts() as $materialCost) {
  203.                 $materialCost->setQuantity($quantity);
  204.             }
  205.         }
  206.         $em $this->managerRegistry->getManager();
  207.         $em->flush();
  208.         return [
  209.             'success' => true,
  210.             'message' => $message $message 'Menge im Warenkorb aktualisiert.',
  211.         ];
  212.     }
  213.     /**
  214.      * @Route("/remove", name="rest_cart_remove", methods="DELETE")
  215.      * @SWG\Delete(
  216.      *     produces={"application/json"},
  217.      *     consumes={"application/x-www-form-urlencoded"}
  218.      * )
  219.      * @SWG\Parameter(name="courseOccurrence", in="body", required=true, schema=@SWG\Schema(type="integer"))
  220.      * @SWG\Response(
  221.      *     response=200,
  222.      *     description="Returns json containing a confirmation message",
  223.      *     @SWG\Schema(
  224.      *         type="object",
  225.      *         @SWG\Property(property="success", type="boolean", description="Flag if request was successful"),
  226.      *         @SWG\Property(property="message", type="string", description="Response message."),
  227.      *     )
  228.      * )
  229.      * @SWG\Response(
  230.      *     response=400,
  231.      *     description="Returned if request parameter were invalid."
  232.      * )
  233.      * @SWG\Response(
  234.      *     response=403,
  235.      *     description="Returned if access to course occurrence was denied."
  236.      * )
  237.      * @SWG\Response(
  238.      *     response=404,
  239.      *     description="Returned if course occurrence was not found."
  240.      * )
  241.      * @SWG\Tag(name="rest")
  242.      * @View(serializerGroups={"public"})
  243.      */
  244.     public function remove(Request $request)
  245.     {
  246.         $courseOccurrenceId $request->get('courseOccurrence');
  247.         if (!is_numeric($courseOccurrenceId)) {
  248.             return $this->json([
  249.                 'success' => false,
  250.                 'message' => 'Es wurden ungültige Werte übergeben',
  251.                 'errors' => ['courseOccurrence' => 'Dieser Wert muss ein Integer sein.'],
  252.             ], 400);
  253.         }
  254.         $courseOccurrence $this->getCourseOccurrence($courseOccurrenceId);
  255.         $cart $this->getCart();
  256.         $em $this->managerRegistry->getManager();
  257.         $cartItem $this->cartService->getCartItemIfExists($courseOccurrence$cart);
  258.         if (!$cartItem) {
  259.             throw $this->createNotFoundException('Der angeforderte Kurs befindet sich nicht im Warenkorb.');
  260.         }
  261.         if ($cartItem->getMaterialCosts()) {
  262.             foreach ($cartItem->getMaterialCosts() as $materialCost) {
  263.                 $em->remove($materialCost);
  264.             }
  265.         }
  266.         $cart->removeItem($cartItem);
  267.         $em->remove($cartItem);
  268.         $em->flush();
  269.         return [
  270.             'success' => true,
  271.             'message' => 'Der Kurs wurde aus dem Warenkorb entfernt.',
  272.         ];
  273.     }
  274.     /**
  275.      * @Route("/show", name="rest_cart_show", methods="GET")
  276.      * @SWG\Get(
  277.      *     produces={"application/json"},
  278.      *     @SWG\Parameter(name="limit", in="query", type="integer"),
  279.      *     @SWG\Parameter(name="offset", in="query", type="integer"),
  280.      * )
  281.      * @QueryParam(
  282.      *     name="limit",
  283.      *     requirements="\d+",
  284.      *     default="100",
  285.      * )
  286.      * @QueryParam(
  287.      *     name="offset",
  288.      *     requirements="\d+",
  289.      *     default="0",
  290.      * )
  291.      * @QueryParam(
  292.      *     name="order",
  293.      *     requirements="asc|desc",
  294.      *     default="asc",
  295.      *     description="Possible values: asc|desc",
  296.      * )
  297.      * @QueryParam(
  298.      *     name="orderby",
  299.      *     requirements="title|price|priceSum|quantity",
  300.      *     default="title",
  301.      *     description="Possible values: title|price|priceSum|quantity",
  302.      * )
  303.      * @SWG\Response(
  304.      *     response=200,
  305.      *     description="Returns cart content in json format.",
  306.      *     @Model(type=Cart::class, groups={"personal"})
  307.      * )
  308.      * @SWG\Tag(name="rest")
  309.      * @View(serializerGroups={"personal"})
  310.      */
  311.     public function show(
  312.         ParamFetcher $paramFetcher
  313.         CartItemRepository $cartItemRepo,
  314.         Connection $connection,
  315.         CourseDataRepository $courseDataRepository
  316.         CourseFieldRepository $courseFieldRepository,
  317.         ConfigurationService $configService
  318.       
  319.         )
  320.     { 
  321.         $order $paramFetcher->get('order');
  322.         $orderby $paramFetcher->get('orderby');
  323.         $limit $paramFetcher->get('limit');
  324.         $offset $paramFetcher->get('offset');
  325.         $cart $this->getCart();
  326.         if ($cart->getId()) {
  327.             $cartItems $cartItemRepo->findBy(['cart' => $cart'courseItem' => null], [$orderby => $order], $limit$offset);
  328.             foreach ($cartItems as $cartItem) {
  329.                 $sqlCourse 'SELECT 
  330.                 c.id,
  331.                 c.title,
  332.                 c.description,
  333.                 c.category_id,
  334.                 c.series_id,
  335.                 c.type_id
  336.               FROM 
  337.                 course c
  338.               WHERE 
  339.                 c.id = :courseId';
  340. $stmtCourse $connection->prepare($sqlCourse);
  341. $stmtCourse->bindValue('courseId'$cartItem->getCourse()->getId());
  342. $stmtCourse->executeQuery();
  343. $courseData $stmtCourse->fetchAllAssociative();
  344.   // Falls der Kurs nicht existiert, überspringen
  345.   if (!$courseData) {
  346.     continue;
  347. }
  348.                 $sql 'SELECT
  349.                 f.*,
  350.                 d.value_text,
  351.                 d.value_integer
  352.             FROM
  353.                 course_field f
  354.             LEFT JOIN
  355.                 course_data d
  356.             ON 
  357.             d.field_id = f.id AND
  358.             d.course_id = :courseId
  359.             WHERE f.certificate = 0';
  360.            
  361.                 $stmt $connection->prepare($sql);
  362.                 $stmt->bindValue(
  363.                     'courseId',
  364.                     $cartItem->getCourse()->getId()
  365.                 );
  366.                 $stmt->executeQuery();
  367.                 $result $stmt->fetchAll();
  368.                 $fields = [];
  369.         
  370.                 foreach ($result as $field) {
  371.                        
  372.                     $fields[] = [
  373.                         'id' => $field['id'],
  374.                         'name' => $field['name'],
  375.                         'value' => !empty($field['value_integer']) ? $field['value_integer'] : $field['value_text'],
  376.                     ];
  377.                 }
  378.                 $fields[] = [
  379.                     'id' => 'category_id',
  380.                     'name' => 'Category ID',
  381.                     'value' => $courseData[0]['category_id'],
  382.                 ];
  383.                 $fields[] = [
  384.                     'id' => 'series_id',
  385.                     'name' => 'Series ID',
  386.                     'value' => $courseData[0]['series_id'],
  387.                 ];
  388.                 $fields[] = [
  389.                     'id' => 'type_id',
  390.                     'name' => 'Type ID',
  391.                     'value' => $courseData[0]['type_id'],
  392.                 ];
  393.                 
  394.                 $cartItem->setField($fields);
  395.                 
  396.                 $cartItem->setField($fields); // oder $cartItem->field = 'yes';
  397.                  }
  398.             $cart->setItems($cartItems);
  399.         }
  400.         return $cart;
  401.     }
  402.     /**
  403.      * Get course occurrence by id. It will be checked if entity exists and access is allowed.
  404.      *
  405.      * @param $courseOccurrenceId
  406.      * @return CourseOccurrence|null
  407.      */
  408.     protected function getCourseOccurrence($courseOccurrenceId)
  409.     {
  410.         $courseOccurrence $this->courseOccurrenceRepo->findOneBy(['id' => $courseOccurrenceId]);
  411.         if (!$courseOccurrence) {
  412.             throw $this->createNotFoundException('The requested course occurrence does not exist.');
  413.         }
  414.         #$this->denyAccessUnlessGranted('frontend_client_allowed', $courseOccurrence);
  415.         return $courseOccurrence;
  416.     }
  417.     
  418.     private function createDescription($field$option)
  419.     {
  420.         switch ($option) {
  421.             case 'course':
  422.                 if (!empty($field['certificate'])) {
  423.                     $field['name'] = $this->generateHTMLForDescription(
  424.                         $field['name'],
  425.                         'für den Kurs und das Zertifikat'
  426.                     );
  427.                 } else {
  428.                     $field['name'] = $this->generateHTMLForDescription(
  429.                         $field['name'],
  430.                         'für den Kurs'
  431.                     );
  432.                 }
  433.                 break;
  434.             case 'certificate':
  435.                 $field['name'] = $this->generateHTMLForDescription(
  436.                     $field['name'],
  437.                     'für das Zertifikat'
  438.                 );
  439.                 break;
  440.             default:
  441.                 break;
  442.         }
  443.         return $field;
  444.     }
  445.     private function generateHTMLForDescription($name$text)
  446.     {
  447.         return '<strong>' $name '</strong>' .  '<span style="font-size: 0.7rem"> (' $text ')</span>';
  448.     }
  449. }