<?php
namespace App\Controller\Rest;
use App\Entity\CartItem;
use App\Service\CartService;
use Swagger\Annotations as SWG;
use App\Entity\CourseOccurrence;
use App\Repository\PersonRepository;
use App\Repository\CartItemRepository;
use FOS\RestBundle\Request\ParamFetcher;
use Doctrine\Persistence\ManagerRegistry;
use Nelmio\ApiDocBundle\Annotation\Model;
use App\Repository\OAuth\ClientRepository;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Security;
use App\Repository\CourseOccurrenceRepository;
use App\Repository\OAuth\AccessTokenRepository;
use FOS\RestBundle\Controller\Annotations\View;
use Symfony\Component\Routing\Annotation\Route;
use App\Repository\CourseOccurrenceTimeRepository;
use FOS\RestBundle\Controller\Annotations\QueryParam;
use App\Controller\Traits\SingleOccurrenceRequestValidatable;
use League\Bundle\OAuth2ServerBundle\Manager\AccessTokenManagerInterface;
/**
* @Route("/rest/cart")
*/
class CartRestController extends AbstractRestCartableController
{
use SingleOccurrenceRequestValidatable;
private $courseOccurrenceRepo;
protected $managerRegistry;
public function __construct(
ClientRepository $clientRepository,
AccessTokenManagerInterface $accessTokenManagerInterface,
AccessTokenRepository $accessTokenRepository,
Security $security,
CartService $cartService,
PersonRepository $personRepo,
CourseOccurrenceRepository $courseOccurrenceRepo,
ManagerRegistry $managerRegistry
) {
parent::__construct($clientRepository, $accessTokenManagerInterface, $accessTokenRepository, $security, $managerRegistry, $cartService, $personRepo);
$this->courseOccurrenceRepo = $courseOccurrenceRepo;
$this->managerRegistry = $managerRegistry;
}
/**
* @Route("/add", name="rest_cart_add", methods="PUT")
* @SWG\Put(
* produces={"application/json"},
* consumes={"application/x-www-form-urlencoded"}
* )
* @SWG\Parameter(name="courseOccurrence", in="body", required=true, schema=@SWG\Schema(type="integer"))
* @SWG\Parameter(name="quantity", in="body", required=true, schema=@SWG\Schema(type="integer"))
* @SWG\Parameter(name="courseOccurrenceTime", in="body", required=false, schema=@SWG\Schema(type="integer"))
* @SWG\Response(
* response=200,
* description="Returns json containing a confirmation message",
* @SWG\Schema(
* type="object",
* @SWG\Property(property="success", type="boolean", description="Flag if request was successful"),
* @SWG\Property(property="message", type="string", description="Response message."),
* )
* )
* @SWG\Response(
* response=400,
* description="Returned if request parameter were invalid."
* )
* @SWG\Response(
* response=403,
* description="Returned if access to course occurrence was denied."
* )
* @SWG\Response(
* response=404,
* description="Returned if course occurrence was not found."
* )
* @SWG\Tag(name="rest")
* @View(serializerGroups={"public"})
*/
public function add(
Request $request,
CourseOccurrenceTimeRepository $courseOccurrenceTimeRepository
)
{
$courseOccurrenceId = $request->get('courseOccurrence');
$quantity = $request->get('quantity');
if (empty($quantity)) {
throw new \Exception(sprintf('Der Parameter „%s“ fehlt leider.', 'quantity'));
}
$violation = $this->validateSingleOccurrenceRequest($courseOccurrenceId, $quantity);
if ($violation !== null) {
return $violation;
}
$courseOccurrence = $this->getCourseOccurrence($courseOccurrenceId);
$courseOccurrenceTimeId = null;
// Validate course template availability
if ($courseOccurrence->getCourse()->getCourseNature() == 'CourseTemplate') {
// Obtain course occurrence time id
$courseOccurrenceTimeId = $request->get('courseOccurrenceTime');
if (empty($courseOccurrenceTimeId)) {
throw new \Exception(sprintf('Der Parameter „%s“ fehlt leider.', 'courseOccurrenceTime'));
}
// Fetch time
$courseOccurrenceTime = $courseOccurrenceTimeRepository->find($courseOccurrenceTimeId);
if ($courseOccurrenceTime === null) {
throw $this->createNotFoundException('Der angegebene Zeit-Slot konnte nicht gefunden werden.');
}
if ($courseOccurrenceTime->getAvailability() == 'NotAvailable') {
throw new \Exception(sprintf('Time is not available.'));
}
// Todo check collision with booked courses
} else {
$courseOccurrenceTime = null;
if (!$courseOccurrence->isAvailable()) {
throw $this->createNotFoundException('Dieser Kurs kann nicht in den Warenkorb gelegt werden.');
}
}
$em = $this->managerRegistry->getManager();
$cart = $this->getCart();
if (!$cart->getId()) {
$em->flush();
}
$cartItem = $this->cartService->getCartItemIfExists($courseOccurrence, $cart, false, $courseOccurrenceTimeId);
if ($cartItem) {
if ($courseOccurrence->getCourse()->getCourseNature() != 'CourseTemplate') {
$cartItem->increaseQuantity($quantity);
foreach ($cartItem->getMaterialCosts() as $materialCost) {
$materialCost->increaseQuantity($quantity);
}
}
} else {
$cartItem = CartItem::createWithCart($cart, $courseOccurrence, $quantity, $courseOccurrenceTime);
$em->persist($cartItem);
if ($courseOccurrence->getMaterialCost() > 0) {
$materialCost = CartItem::createWithCartItem($cartItem);
$em->persist($materialCost);
}
}
$em->flush();
return [
'success' => true,
'message' => $quantity . ($quantity > 1 ? ' Kurse' : ' Kurs') . ' in den Warenkorb gelegt.',
];
}
/**
* @Route("/set-quantity", name="rest_cart_set-quantity", methods="PUT")
* @SWG\Put(
* produces={"application/json"},
* consumes={"application/x-www-form-urlencoded"}
* )
* @SWG\Parameter(name="courseOccurrence", in="body", required=true, schema=@SWG\Schema(type="integer"))
* @SWG\Parameter(name="quantity", in="body", required=true, schema=@SWG\Schema(type="integer"))
* @SWG\Response(
* response=200,
* description="Returns json containing a confirmation message"
* )
* @SWG\Response(
* response=400,
* description="Returned if request parameter were invalid."
* )
* @SWG\Response(
* response=403,
* description="Returned if access to course occurrence was denied."
* )
* @SWG\Response(
* response=404,
* description="Returned if course occurrence was not found."
* )
* @SWG\Tag(name="rest")
* @View(serializerGroups={"public"})
*/
public function setQuantity(Request $request)
{
$courseOccurrenceId = $request->get('courseOccurrence');
$quantity = $request->get('quantity');
$violation = $this->validateSingleOccurrenceRequest($courseOccurrenceId, $quantity);
if ($violation !== null) {
return $this->json($violation, 400);
}
$courseOccurrence = $this->getCourseOccurrence($courseOccurrenceId);
$cart = $this->getCart();
$cartItem = $this->cartService->getCartItemIfExists($courseOccurrence, $cart);
if (!$cartItem) {
throw $this->createNotFoundException('The requested item is not in current cart.');
}
$message = '';
if ($quantity > $courseOccurrence->getFreeSlots()) {
if (!$courseOccurrence->getReservationAllowed()) {
return [
'success' => false,
'message' => 'Es sind keine freien Plätze mehr verfügbar.',
];
}
$message = 'Menge im Warenkorb aktualisiert. Es sind nicht mehr genug Plätze verfügbar. Ihre Anmeldung wird auf die Warteliste gestellt.';
}
$cartItem->setQuantity($quantity);
if ($cartItem->getMaterialCosts()) {
foreach ($cartItem->getMaterialCosts() as $materialCost) {
$materialCost->setQuantity($quantity);
}
}
$em = $this->managerRegistry->getManager();
$em->flush();
return [
'success' => true,
'message' => $message ? $message : 'Menge im Warenkorb aktualisiert.',
];
}
/**
* @Route("/remove", name="rest_cart_remove", methods="DELETE")
* @SWG\Delete(
* produces={"application/json"},
* consumes={"application/x-www-form-urlencoded"}
* )
* @SWG\Parameter(name="courseOccurrence", in="body", required=true, schema=@SWG\Schema(type="integer"))
* @SWG\Response(
* response=200,
* description="Returns json containing a confirmation message",
* @SWG\Schema(
* type="object",
* @SWG\Property(property="success", type="boolean", description="Flag if request was successful"),
* @SWG\Property(property="message", type="string", description="Response message."),
* )
* )
* @SWG\Response(
* response=400,
* description="Returned if request parameter were invalid."
* )
* @SWG\Response(
* response=403,
* description="Returned if access to course occurrence was denied."
* )
* @SWG\Response(
* response=404,
* description="Returned if course occurrence was not found."
* )
* @SWG\Tag(name="rest")
* @View(serializerGroups={"public"})
*/
public function remove(Request $request)
{
$courseOccurrenceId = $request->get('courseOccurrence');
if (!is_numeric($courseOccurrenceId)) {
return $this->json([
'success' => false,
'message' => 'Es wurden ungültige Werte übergeben',
'errors' => ['courseOccurrence' => 'Dieser Wert muss ein Integer sein.'],
], 400);
}
$courseOccurrence = $this->getCourseOccurrence($courseOccurrenceId);
$cart = $this->getCart();
$em = $this->managerRegistry->getManager();
$cartItem = $this->cartService->getCartItemIfExists($courseOccurrence, $cart);
if (!$cartItem) {
throw $this->createNotFoundException('Der angeforderte Kurs befindet sich nicht im Warenkorb.');
}
if ($cartItem->getMaterialCosts()) {
foreach ($cartItem->getMaterialCosts() as $materialCost) {
$em->remove($materialCost);
}
}
$cart->removeItem($cartItem);
$em->remove($cartItem);
$em->flush();
return [
'success' => true,
'message' => 'Der Kurs wurde aus dem Warenkorb entfernt.',
];
}
/**
* @Route("/show", name="rest_cart_show", methods="GET")
* @SWG\Get(
* produces={"application/json"},
* @SWG\Parameter(name="limit", in="query", type="integer"),
* @SWG\Parameter(name="offset", in="query", type="integer"),
* )
* @QueryParam(
* name="limit",
* requirements="\d+",
* default="100",
* )
* @QueryParam(
* name="offset",
* requirements="\d+",
* default="0",
* )
* @QueryParam(
* name="order",
* requirements="asc|desc",
* default="asc",
* description="Possible values: asc|desc",
* )
* @QueryParam(
* name="orderby",
* requirements="title|price|priceSum|quantity",
* default="title",
* description="Possible values: title|price|priceSum|quantity",
* )
* @SWG\Response(
* response=200,
* description="Returns cart content in json format.",
* @Model(type=Cart::class, groups={"personal"})
* )
* @SWG\Tag(name="rest")
* @View(serializerGroups={"personal"})
*/
public function show(ParamFetcher $paramFetcher, CartItemRepository $cartItemRepo)
{
$order = $paramFetcher->get('order');
$orderby = $paramFetcher->get('orderby');
$limit = $paramFetcher->get('limit');
$offset = $paramFetcher->get('offset');
$cart = $this->getCart();
if ($cart->getId()) {
$cartItems = $cartItemRepo->findBy(['cart' => $cart, 'courseItem' => null], [$orderby => $order], $limit, $offset);
$cart->setItems($cartItems);
}
return $cart;
}
/**
* Get course occurrence by id. It will be checked if entity exists and access is allowed.
*
* @param $courseOccurrenceId
* @return CourseOccurrence|null
*/
protected function getCourseOccurrence($courseOccurrenceId)
{
$courseOccurrence = $this->courseOccurrenceRepo->findOneBy(['id' => $courseOccurrenceId]);
if (!$courseOccurrence) {
throw $this->createNotFoundException('The requested course occurrence does not exist.');
}
#$this->denyAccessUnlessGranted('frontend_client_allowed', $courseOccurrence);
return $courseOccurrence;
}
}