<?php
namespace Factory\CartBundle\Controller;
use App\Model\Product;
use Factory\CartBundle\Classes\Traits\Controller\ControllerDispatchActionTrait;
use Factory\CartBundle\Classes\CartEvents;
use Factory\CartBundle\Classes\DataMapper\CartDataMapper;
use Factory\CartBundle\Classes\Traits\Controller\GetCartTrait;
use Factory\CartBundle\Event\CartEvent;
use Pimcore\Bundle\EcommerceFrameworkBundle\Exception\VoucherServiceException;
use Pimcore\Bundle\EcommerceFrameworkBundle\Model\CheckoutableInterface;
use Pimcore\Model\DataObject\AbstractObject;
use Pimcore\Model\DataObject\Fieldcollection;
use Pimcore\Model\DataObject\Product\Listing as ProductListing;
use App\Classes\DataMapper\Customer\Address\AddressDataMapper;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
class CartController extends FrontController
{
use GetCartTrait;
use ControllerDispatchActionTrait;
public function __construct(private EventDispatcherInterface $eventDispatcher, private TranslatorInterface $translator)
{
}
#[Template()]
public function indexAction(Request $request)
{
$event = new CartEvent(
null,
[
'cartName' => 'cart'
]
);
$this->eventDispatcher->dispatch($event, CartEvents::CART_BEFORE_FETCH);
if ($event->isStopped()) {
$this->addFlash($event->getMessageType(), $event->getMessage());
if ($event->hasResponse()) {
return $event->getResponse();
}
return;
}
$cart = $this->getCart($event->getArgument('cartName'), $request);
$event = new CartEvent(
$cart
);
$this->eventDispatcher->dispatch($event, CartEvents::CART_AFTER_FETCH);
if ($event->isStopped()) {
$this->addFlash($event->getMessageType(), $event->getMessage());
if ($event->hasResponse()) {
return $event->getResponse();
}
return;
}
if ($request->isXmlHttpRequest() || $request->get('ajax')) {
return $this->respondWithSuccess(
$this->translator->trans('looome.cart-mini'),
(new CartDataMapper($event->getSubject()))->all($request),
200
);
}
if ($user = $this->getUser()) {
$addresses = $user->getAddresses() ?? new Fieldcollection();
$addresses = AddressDataMapper::list($addresses->getItems())->all($request);
$addressesEU = array_filter($addresses, function ($var) {
return ($var['isEU'] == true);
});
$defaultBillingAddressId = $user->getDefaultBillingAddress();
$defaultShippingAddressId = $user->getDefaultShippingAddress();
$checkAddressIsEU = array_filter($addressesEU, function ($var) use ($defaultBillingAddressId, $defaultShippingAddressId){
return (($var['id'] == $defaultBillingAddressId) || ($var['id'] == $defaultShippingAddressId));
});
$isEU = false;
if (count($checkAddressIsEU)) {
$isEU = true;
}
$this->view->isEU = $isEU;
}
$this->view->cartData = (new CartDataMapper($event->getSubject()))->all($request);
$this->view->cart = $cart;
}
public function updateAction(Request $request)
{
$redirect = $request->get('redirect_to');
$quantities = $request->get('quantities', []);
if (empty($quantities)) {
return $this->respondWithError(
$this->translator->trans('factory.cart-bundle.update.missing-param'),
422
);
}
// @todo in future, use service container to get purchasable class
$productListing = new ProductListing;
$productListing->setCondition("o_id IN (?)", [array_keys($quantities)]);
$productListing->setObjectTypes([AbstractObject::OBJECT_TYPE_OBJECT, AbstractObject::OBJECT_TYPE_VARIANT]);
$products = $productListing->load();
foreach ($products as $product) {
if (!$product instanceof CheckoutableInterface) {
return $this->respondWithError(
$this->get('translator')->trans('factory.cart-bundle.update.general-error'),
422
);
}
}
$event = new CartEvent(
$this->getCart(),
[
'products' => $products,
'quantities' => $quantities,
]
);
$this->eventDispatcher->dispatch($event, CartEvents::CART_BEFORE_UPDATE);
if ($event->isStopped()) {
$this->addFlash($event->getMessageType(), $event->getMessage());
if ($event->hasResponse()) {
return $event->getResponse();
}
return $this->redirectBack($request);
}
$cart = $event->getSubject();
$products = $event->getArgument('products');
$quantities = $event->getArgument('quantities');
foreach ($products as $product) {
$quantity = intVal($quantities[strVal($product->getId())]);
if ($quantity > 0) {
$cart->updateItemCount($product->getId(), $quantity);
} else {
$cart->removeItem($product->getId());
}
}
$cart->save();
$event = new CartEvent(
$this->getCart(),
[
'products' => $products,
'quantities' => $quantities,
]
);
$this->eventDispatcher->dispatch($event, CartEvents::CART_AFTER_UPDATE);
if ($event->isStopped()) {
$this->addFlash($event->getMessageType(), $event->getMessage());
if ($event->hasResponse()) {
return $event->getResponse();
}
return $this->redirectBack($request);
}
if ($redirect) {
return $this->redirect($redirect);
}
return $this->respondWithSuccess(
$this->translator->trans('factory.cart-bundle.update.success'),
(new CartDataMapper($cart))->all($request),
200
);
}
public function addAction(Request $request)
{
$redirect = $request->get('redirect_to');
// @todo in future, use service container to get purchasable class
$product = Product::getById($request->get('product'));
if (!$product) {
return $this->respondWithError(
$this->translator->trans('factory.cart-bundle.add.product-404'),
404
);
}
if (!$product instanceof CheckoutableInterface) {
return $this->respondWithError(
$this->translator->trans('factory.cart-bundle.add.general-error'),
422
);
}
$event = new CartEvent(
$this->getCart(),
[
'product' => $product,
'quantity' => $request->get('quantity'),
'itemKey' => null,
'replace' => false,
'params' => [],
'subProducts' => [],
'comment' => null,
]
);
$this->eventDispatcher->dispatch($event, CartEvents::CART_BEFORE_ADD);
if ($event->isStopped()) {
$this->addFlash($event->getMessageType(), $event->getMessage());
if ($event->hasResponse()) {
return $event->getResponse();
}
return $this->redirectBack($request);
}
$cart = $event->getSubject();
$itemKey = $cart->addItem(
$event->getArgument('product'),
$event->getArgument('quantity'),
$event->getArgument('itemKey'),
$event->getArgument('replace'),
$event->getArgument('params'),
$event->getArgument('subProducts'),
$event->getArgument('comment')
);
$cart->save();
$event = new CartEvent(
$this->getCart(),
[
'itemKey' => $itemKey,
]
);
$this->eventDispatcher->dispatch($event, CartEvents::CART_AFTER_ADD);
if ($event->isStopped()) {
$this->addFlash($event->getMessageType(), $event->getMessage());
if ($event->hasResponse()) {
return $event->getResponse();
}
return $this->redirectBack($request);
}
if ($redirect) {
return $this->redirect($redirect);
}
return $this->respondWithSuccess(
$this->translator->trans('factory.cart-bundle.add.success'),
(new CartDataMapper($cart))->all($request),
200
);
}
public function bulkAddAction(Request $request)
{
$redirect = $request->get('redirect_to');
$quantities = $request->get('products', []);
if (empty($quantities)) {
return $this->respondWithError(
$this->translator->trans('factory.cart-bundle.bulk-add.missing-param'),
422
);
}
// @todo in future, use service container to get purchasable class
$productListing = new ProductListing;
$productListing->setCondition("o_id IN (?)", [array_keys($quantities)]);
$productListing->setObjectTypes([AbstractObject::OBJECT_TYPE_OBJECT, AbstractObject::OBJECT_TYPE_VARIANT]);
$products = $productListing->load();
foreach ($products as $product) {
if (!$product instanceof CheckoutableInterface) {
return $this->respondWithError(
$this->translator->trans('factory.cart-bundle.update.general-error'),
422
);
}
}
$event = new CartEvent(
$this->getCart(),
[
'products' => $products,
'quantities' => $quantities,
]
);
$this->eventDispatcher->dispatch($event, CartEvents::CART_BEFORE_BULK_ADD);
if ($event->isStopped()) {
$this->addFlash($event->getMessageType(), $event->getMessage());
if ($event->hasResponse()) {
return $event->getResponse();
}
return $this->redirectBack($request);
}
$cart = $event->getSubject();
$products = $event->getArgument('products');
$quantities = $event->getArgument('quantities');
foreach ($products as $product) {
$quantity = intVal($quantities[strVal($product->getId())]);
if (!$quantity) {
continue;
}
$cart->addItem($product, $quantity);
}
$cart->save();
$event = new CartEvent(
$this->getCart(),
[
'products' => $products,
'quantities' => $quantities,
]
);
$this->eventDispatcher->dispatch($event, CartEvents::CART_AFTER_BULK_ADD);
if ($event->isStopped()) {
$this->addFlash($event->getMessageType(), $event->getMessage());
if ($event->hasResponse()) {
return $event->getResponse();
}
return $this->redirectBack($request);
}
if ($redirect) {
return $this->redirect($redirect);
}
return $this->respondWithSuccess(
$this->translator->trans('factory.cart-bundle.update.success'),
(new CartDataMapper($cart))->all($request),
200
);
}
public function removeAction(Request $request)
{
$redirect = $request->get('redirect_to');
if (empty($request->get('product'))) {
return $this->respondWithError(
$this->get('translator')->trans('factory.cart-bundle.remove.missing-param'),
422
);
}
$event = new CartEvent(
$this->getCart(),
[
'productId' => $request->get('product'),
'itemKey' => $request->get('itemKey', $request->get('product'))
]
);
$this->eventDispatcher->dispatch($event, CartEvents::CART_BEFORE_REMOVE);
if ($event->isStopped()) {
$this->addFlash($event->getMessageType(), $event->getMessage());
if ($event->hasResponse()) {
return $event->getResponse();
}
return $this->redirectBack($request);
}
$cart = $event->getSubject();
$cart->removeItem(
$event->getArgument('itemKey')
);
$cart->save();
$event = new CartEvent(
$this->getCart(),
[
'itemKey' => $event->getArgument('itemKey')
]
);
$this->eventDispatcher->dispatch($event, CartEvents::CART_AFTER_REMOVE);
if ($event->isStopped()) {
$this->addFlash($event->getMessageType(), $event->getMessage());
if ($event->hasResponse()) {
return $event->getResponse();
}
return $this->redirectBack($request);
}
if ($redirect) {
return $this->redirect($redirect);
}
return $this->respondWithSuccess(
$this->translator->trans('factory.cart-bundle.remove.success'),
(new CartDataMapper($cart))->all($request),
200
);
}
public function addCouponCodeAction(Request $request)
{
$redirect = $request->get('redirect_to');
if (empty($request->get('code'))) {
return $this->respondWithError(
$this->translator->trans('factory.cart-bundle.coupon_code_remove.missing-param'),
422
);
}
$event = new CartEvent(
$this->getCart(),
[
'code' => $request->get('code')
]
);
$this->eventDispatcher->dispatch($event, CartEvents::CART_BEFORE_COUPON_CODE_ADD);
if ($event->isStopped()) {
$this->addFlash($event->getMessageType(), $event->getMessage());
if ($event->hasResponse()) {
return $event->getResponse();
}
return $this->redirectBack($request);
}
$cart = $event->getSubject();
try{
$cart->addVoucherToken($event->getArgument('code'));
} catch (\Pimcore\Bundle\EcommerceFrameworkBundle\Exception\VoucherServiceException $e) {
return $this->respondWithError(
$this->translator->trans('factory.cart-bundle.coupon_code_add.invalid-code')
);
} catch (\Exception $e) {
return $this->respondWithError(
$this->translator->trans('factory.cart-bundle.coupon_code_add.error')
);
}
$cart->save();
$event = new CartEvent(
$this->getCart(),
[
'code' => $event->getArgument('code')
]
);
$this->eventDispatcher->dispatch($event, CartEvents::CART_AFTER_COUPON_CODE_ADD);
if ($event->isStopped()) {
$this->addFlash($event->getMessageType(), $event->getMessage());
if ($event->hasResponse()) {
return $event->getResponse();
}
return $this->redirectBack($request);
}
if ($redirect) {
return $this->redirect($redirect);
}
return $this->respondWithSuccess(
$this->translator->trans('factory.cart-bundle.coupon_code_add.success'),
(new CartDataMapper($cart))->all($request),
200
);
}
public function removeCouponCodeAction(Request $request)
{
$redirect = $request->get('redirect_to');
if (empty($request->get('code'))) {
return $this->respondWithError(
$this->translator->trans('factory.cart-bundle.coupon_code_add.missing-param'),
422
);
}
$event = new CartEvent(
$this->getCart(),
[
'code' => $request->get('code')
]
);
$this->eventDispatcher->dispatch($event, CartEvents::CART_BEFORE_COUPON_CODE_REMOVE);
if ($event->isStopped()) {
$this->addFlash($event->getMessageType(), $event->getMessage());
if ($event->hasResponse()) {
return $event->getResponse();
}
return $this->redirectBack($request);
}
$cart = $event->getSubject();
try {
$cart->removeVoucherToken($event->getArgument('code'));
} catch (VoucherServiceException $e) {
return $this->respondWithError(
$this->translator->trans('factory.cart-bundle.coupon_code_remove.invalid-code')
);
} catch (\Exception $e) {
return $this->respondWithError(
$this->translator->trans('factory.cart-bundle.coupon_code_remove.error')
);
}
$cart->save();
$event = new CartEvent(
$this->getCart(),
[
'code' => $event->getArgument('code')
]
);
$this->translator->dispatch(CartEvents::CART_AFTER_COUPON_CODE_REMOVE, $event);
if ($event->isStopped()) {
$this->addFlash($event->getMessageType(), $event->getMessage());
if ($event->hasResponse()) {
return $event->getResponse();
}
return $this->redirectBack($request);
}
if ($redirect) {
return $this->redirect($redirect);
}
return $this->respondWithSuccess(
$this->translator->trans('factory.cart-bundle.coupon_code_remove.success'),
(new CartDataMapper($cart))->all($request),
200
);
}
public function applyVoucherCodeAction(Request $request)
{
$request->request->set('code', $request->get('voucher-code'));
return $this->addCouponCodeAction($request);
}
}