src/Eccube/Service/CartService.php line 152

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of EC-CUBE
  4.  *
  5.  * Copyright(c) EC-CUBE CO.,LTD. All Rights Reserved.
  6.  *
  7.  * http://www.ec-cube.co.jp/
  8.  *
  9.  * For the full copyright and license information, please view the LICENSE
  10.  * file that was distributed with this source code.
  11.  */
  12. namespace Eccube\Service;
  13. use Doctrine\ORM\EntityManagerInterface;
  14. use Doctrine\ORM\UnitOfWork;
  15. use Eccube\Entity\Cart;
  16. use Eccube\Entity\CartItem;
  17. use Eccube\Entity\Customer;
  18. use Eccube\Entity\ItemHolderInterface;
  19. use Eccube\Entity\ProductClass;
  20. use Eccube\Repository\CartRepository;
  21. use Eccube\Repository\OrderRepository;
  22. use Eccube\Repository\ProductClassRepository;
  23. use Eccube\Service\Cart\CartItemAllocator;
  24. use Eccube\Service\Cart\CartItemComparator;
  25. use Eccube\Util\StringUtil;
  26. use Plugin\ShelvingOption4\Entity\ShelvingOptionCartItem;    //@##ADD 2021-11-05 upseek
  27. use Symfony\Component\HttpFoundation\Session\SessionInterface;
  28. use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
  29. use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
  30. class CartService
  31. {
  32.     /**
  33.      * @var Cart[]
  34.      */
  35.     protected $carts;
  36.     /**
  37.      * @var SessionInterface
  38.      */
  39.     protected $session;
  40.     /**
  41.      * @var \Doctrine\ORM\EntityManagerInterface
  42.      */
  43.     protected $entityManager;
  44.     /**
  45.      * @var ItemHolderInterface
  46.      *
  47.      * @deprecated
  48.      */
  49.     protected $cart;
  50.     /**
  51.      * @var ProductClassRepository
  52.      */
  53.     protected $productClassRepository;
  54.     /**
  55.      * @var CartRepository
  56.      */
  57.     protected $cartRepository;
  58.     /**
  59.      * @var CartItemComparator
  60.      */
  61.     protected $cartItemComparator;
  62.     /**
  63.      * @var CartItemAllocator
  64.      */
  65.     protected $cartItemAllocator;
  66.     /**
  67.      * @var OrderRepository
  68.      */
  69.     protected $orderRepository;
  70.     /**
  71.      * @var TokenStorageInterface
  72.      */
  73.     protected $tokenStorage;
  74.     /**
  75.      * @var AuthorizationCheckerInterface
  76.      */
  77.     protected $authorizationChecker;
  78. //@##ADD START 2021-11-05 upseek
  79.     /**
  80.      * @var CalculatePriceService;
  81.      */
  82.     protected $calculatePriceService;
  83. //@##ADD END
  84.     /**
  85.      * CartService constructor.
  86.      */
  87.     public function __construct(
  88.         SessionInterface $session,
  89.         EntityManagerInterface $entityManager,
  90.         ProductClassRepository $productClassRepository,
  91.         CartRepository $cartRepository,
  92.         CartItemComparator $cartItemComparator,
  93.         CartItemAllocator $cartItemAllocator,
  94.         OrderRepository $orderRepository,
  95.         TokenStorageInterface $tokenStorage,
  96.         AuthorizationCheckerInterface $authorizationChecker,
  97.         CalculatePriceService $calculatePriceService    //@##ADD 2021-11-05 upssek
  98.     ) {
  99.         $this->session $session;
  100.         $this->entityManager $entityManager;
  101.         $this->productClassRepository $productClassRepository;
  102.         $this->cartRepository $cartRepository;
  103.         $this->cartItemComparator $cartItemComparator;
  104.         $this->cartItemAllocator $cartItemAllocator;
  105.         $this->orderRepository $orderRepository;
  106.         $this->tokenStorage $tokenStorage;
  107.         $this->authorizationChecker $authorizationChecker;
  108.         $this->calculatePriceService $calculatePriceService;    //@##ADD 2021-11-05 upseek
  109.     }
  110.     /**
  111.      * 現在のカートの配列を取得する.
  112.      *
  113.      * 本サービスのインスタンスのメンバーが空の場合は、DBまたはセッションからカートを取得する
  114.      *
  115.      * @param bool $empty_delete true の場合、商品明細が空のカートが存在した場合は削除する
  116.      *
  117.      * @return Cart[]
  118.      */
  119.     public function getCarts($empty_delete false)
  120.     {
  121.         if (null !== $this->carts) {
  122.             if ($empty_delete) {
  123.                 $cartKeys = [];
  124.                 foreach (array_keys($this->carts) as $index) {
  125.                     $Cart $this->carts[$index];
  126.                     if ($Cart->getItems()->count() > 0) {
  127.                         $cartKeys[] = $Cart->getCartKey();
  128.                     } else {
  129.                         $this->entityManager->remove($this->carts[$index]);
  130.                         $this->entityManager->flush();
  131.                         unset($this->carts[$index]);
  132.                     }
  133.                 }
  134.                 $this->session->set('cart_keys'$cartKeys);
  135.             }
  136.             return $this->carts;
  137.         }
  138.         if ($this->getUser()) {
  139.             $this->carts $this->getPersistedCarts();
  140.         } else {
  141.             $this->carts $this->getSessionCarts();
  142.         }
  143.         return $this->carts;
  144.     }
  145.     /**
  146.      * 永続化されたカートを返す
  147.      *
  148.      * @return Cart[]
  149.      */
  150.     public function getPersistedCarts()
  151.     {
  152.         return $this->cartRepository->findBy(['Customer' => $this->getUser()]);
  153.     }
  154.     /**
  155.      * セッションにあるカートを返す
  156.      *
  157.      * @return Cart[]
  158.      */
  159.     public function getSessionCarts()
  160.     {
  161.         $cartKeys $this->session->get('cart_keys', []);
  162.         if (empty($cartKeys)) {
  163.             return [];
  164.         }
  165.         return $this->cartRepository->findBy(['cart_key' => $cartKeys], ['id' => 'ASC']);
  166.     }
  167.     /**
  168.      * 会員が保持する永続化されたカートと、非会員時のカートをマージする.
  169.      */
  170.     public function mergeFromPersistedCart()
  171.     {
  172.         $persistedCarts $this->getPersistedCarts();
  173.         $sessionCarts $this->getSessionCarts();
  174.         $CartItems = [];
  175.         // 永続化されたカートとセッションのカートが同一の場合はマージしない #4574
  176.         $cartKeys $this->session->get('cart_keys', []);
  177.         if ((count($persistedCarts) > 0) && !in_array($persistedCarts[0]->getCartKey(), $cartKeystrue)) {
  178.             foreach ($persistedCarts as $Cart) {
  179.                 $CartItems $this->mergeCartItems($Cart->getCartItems(), $CartItems);
  180.             }
  181.         }
  182.         // セッションにある非会員カートとDBから取得した会員カートをマージする.
  183.         foreach ($sessionCarts as $Cart) {
  184.             $CartItems $this->mergeCartItems($Cart->getCartItems(), $CartItems);
  185.         }
  186.         $this->restoreCarts($CartItems);
  187.     }
  188.     /**
  189.      * @return Cart|null
  190.      */
  191.     public function getCart()
  192.     {
  193.         $Carts $this->getCarts();
  194.         if (empty($Carts)) {
  195.             return null;
  196.         }
  197.         $cartKeys $this->session->get('cart_keys', []);
  198.         $Cart null;
  199.         if (count($cartKeys) > 0) {
  200.             foreach ($Carts as $cart) {
  201.                 if ($cart->getCartKey() === current($cartKeys)) {
  202.                     $Cart $cart;
  203.                     break;
  204.                 }
  205.             }
  206.         } else {
  207.             $Cart $Carts[0];
  208.         }
  209.         return $Cart;
  210.     }
  211.     /**
  212.      * @param CartItem[] $cartItems
  213.      *
  214.      * @return CartItem[]
  215.      */
  216.     protected function mergeAllCartItems($cartItems = [])
  217.     {
  218.         /** @var CartItem[] $allCartItems */
  219.         $allCartItems = [];
  220.         foreach ($this->getCarts() as $Cart) {
  221.             $allCartItems $this->mergeCartItems($Cart->getCartItems(), $allCartItems);
  222.         }
  223.         return $this->mergeCartItems($cartItems$allCartItems);
  224.     }
  225.     /**
  226.      * @param $cartItems
  227.      * @param $allCartItems
  228.      *
  229.      * @return array
  230.      */
  231.     protected function mergeCartItems($cartItems$allCartItems)
  232.     {
  233.         foreach ($cartItems as $item) {
  234.             $itemExists false;
  235.             foreach ($allCartItems as $itemInArray) {
  236.                 // 同じ明細があればマージする
  237.                 if ($this->cartItemComparator->compare($item$itemInArray)) {
  238.                     $itemInArray->setQuantity($itemInArray->getQuantity() + $item->getQuantity());
  239.                     $itemExists true;
  240.                     break;
  241.                 }
  242.             }
  243.             if (!$itemExists) {
  244.                 $allCartItems[] = $item;
  245.             }
  246.         }
  247.         return $allCartItems;
  248.     }
  249.     protected function restoreCarts($cartItems)
  250.     {
  251.         foreach ($this->getCarts() as $Cart) {
  252.             foreach ($Cart->getCartItems() as $i) {
  253. //@##ADD START 2021-11-05 upseek
  254. //log_warning('@@@ CartService.restoreCarts1');
  255.                 $shelvingOption $i->getShelvingOption();
  256.                 if($shelvingOption != null) {
  257.                     $this->entityManager->remove($shelvingOption);
  258.                     $this->entityManager->flush();
  259.                 } else {
  260. //log_warning('@@@ woops1');
  261.                 }
  262. //@##ADD END
  263.                 $this->entityManager->remove($i);
  264.                 $this->entityManager->flush();
  265.             }
  266.             $this->entityManager->remove($Cart);
  267.             $this->entityManager->flush();
  268.         }
  269.         $this->carts = [];
  270.         /** @var Cart[] $Carts */
  271.         $Carts = [];
  272.         foreach ($cartItems as $item) {
  273.             $allocatedId $this->cartItemAllocator->allocate($item);
  274.             $cartKey $this->createCartKey($allocatedId$this->getUser());
  275.             if (isset($Carts[$cartKey])) {
  276.                 $Cart $Carts[$cartKey];
  277.                 $Cart->addCartItem($item);
  278.                 $item->setCart($Cart);
  279.             } else {
  280.                 /** @var Cart $Cart */
  281.                 $Cart $this->cartRepository->findOneBy(['cart_key' => $cartKey]);
  282.                 if ($Cart) {
  283.                     foreach ($Cart->getCartItems() as $i) {
  284. //@##ADD START 2021-11-05 upseek
  285. //log_warning('@@@ CartService.restoreCarts2');
  286.                         $shelvingOption $i->getShelvingOption();
  287.                         if($shelvingOption != null) {
  288.                             $this->entityManager->remove($shelvingOption);
  289.                             $this->entityManager->flush();
  290.                         } else {
  291. //log_warning('@@@ woops2');
  292.                         }
  293. //@##ADD END
  294.                         $this->entityManager->remove($i);
  295.                         $this->entityManager->flush();
  296.                     }
  297.                     $this->entityManager->remove($Cart);
  298.                     $this->entityManager->flush();
  299.                 }
  300.                 $Cart = new Cart();
  301.                 $Cart->setCartKey($cartKey);
  302.                 $Cart->addCartItem($item);
  303.                 $item->setCart($Cart);
  304.                 $Carts[$cartKey] = $Cart;
  305.             }
  306.         }
  307.         $this->carts array_values($Carts);
  308.     }
  309.     /**
  310.      * カートに商品を追加します.
  311.      *
  312.      * @param $ProductClass ProductClass 商品規格
  313.      * @param $quantity int 数量
  314.      * @param $ShelvingOptin ShelvingOptionCartItem カスタマイズ
  315.      *
  316.      * @return bool 商品を追加できた場合はtrue
  317.      */
  318. //@##CHG START 2021-11-05 upseek
  319. //    public function addProduct($ProductClass, $quantity = 1)
  320.     public function addProduct($ProductClass$quantity 1$ShelvingOption null)
  321. //@##CHG END
  322.     {
  323.         if (!$ProductClass instanceof ProductClass) {
  324.             $ProductClassId $ProductClass;
  325.             $ProductClass $this->entityManager
  326.                 ->getRepository(ProductClass::class)
  327.                 ->find($ProductClassId);
  328.             if (is_null($ProductClass)) {
  329.                 return false;
  330.             }
  331.         }
  332. //@##ADD START 2021-11-05 upseek
  333.         if (!$ShelvingOption instanceof ShelvingOptionCartItem) {
  334.             $ShelvingOption $ProductClass->getProduct()->getShelvingOption();
  335.             if($ShelvingOption) {
  336.                 $ShelvingOption $ShelvingOption->convertForCartItem(); //@##ADD 2022-10-26 upseek
  337.             }
  338.         }
  339. //@##ADD END 2021-11-05 upseek
  340.         $ClassCategory1 $ProductClass->getClassCategory1();
  341.         if ($ClassCategory1 && !$ClassCategory1->isVisible()) {
  342.             return false;
  343.         }
  344.         $ClassCategory2 $ProductClass->getClassCategory2();
  345.         if ($ClassCategory2 && !$ClassCategory2->isVisible()) {
  346.             return false;
  347.         }
  348. //@##ADD START 2021-11-05 upseek
  349.         //販売種別:2=オーダー商品
  350.         if($ProductClass->getSaleType()->getId() == 2) {
  351.             $priceIncTax $this->calculatePriceService->calculate($ShelvingOptiontrue);
  352.         } else {
  353.             $priceIncTax $ProductClass->getPrice02IncTax();
  354.         }
  355.         log_warning('addProduct saleType.id=' $ProductClass->getSaleType()->getId() . ' priceIncTax=[' $priceIncTax ']');
  356. //@##ADD END
  357.         $newItem = new CartItem();
  358.         $newItem->setQuantity($quantity);
  359. //@##CHG START 2021-11-05 upseek
  360. //        $newItem->setPrice($ProductClass->getPrice02IncTax());
  361.         $newItem->setPrice($priceIncTax);
  362. //@##CHG NED
  363.         $newItem->setProductClass($ProductClass);
  364. //@##ADD START 2021-11-05 upseek
  365.         //販売種別:2=オーダー商品
  366.         if($ProductClass->getSaleType()->getId() == 2) {
  367.             $newItem->setShelvingOption($ShelvingOption);
  368.         }
  369. //@##ADD END
  370.         $allCartItems $this->mergeAllCartItems([$newItem]);
  371.         $this->restoreCarts($allCartItems);
  372.         return true;
  373.     }
  374.     public function removeProduct($ProductClass)
  375.     {
  376.         if (!$ProductClass instanceof ProductClass) {
  377.             $ProductClassId $ProductClass;
  378.             $ProductClass $this->entityManager
  379.                 ->getRepository(ProductClass::class)
  380.                 ->find($ProductClassId);
  381.             if (is_null($ProductClass)) {
  382.                 return false;
  383.             }
  384.         }
  385.         $removeItem = new CartItem();
  386.         $removeItem->setPrice($ProductClass->getPrice02IncTax());
  387.         $removeItem->setProductClass($ProductClass);
  388.         $allCartItems $this->mergeAllCartItems();
  389.         $foundIndex = -1;
  390.         foreach ($allCartItems as $index => $itemInCart) {
  391.             if ($this->cartItemComparator->compare($itemInCart$removeItem)) {
  392.                 $foundIndex $index;
  393.                 break;
  394.             }
  395.         }
  396.         array_splice($allCartItems$foundIndex1);
  397.         $this->restoreCarts($allCartItems);
  398.         return true;
  399.     }
  400.     public function save()
  401.     {
  402.         $cartKeys = [];
  403.         foreach ($this->carts as $Cart) {
  404.             $Cart->setCustomer($this->getUser());
  405.             $this->entityManager->persist($Cart);
  406.             foreach ($Cart->getCartItems() as $item) {
  407.                 $this->entityManager->persist($item);
  408. //@##ADD START 2021-11-05 upseek
  409. //log_warning('@@@@ CartService.save');
  410.                 $shelvingOption $item->getShelvingOption();
  411.                 if($shelvingOption != null) {
  412.                     $shelvingOption->setCartItem($item);
  413.                     $this->entityManager->persist($shelvingOption);
  414.                 }
  415. //@##ADD END
  416.             }
  417.             $this->entityManager->flush();
  418.             $cartKeys[] = $Cart->getCartKey();
  419.         }
  420.         $this->session->set('cart_keys'$cartKeys);
  421.         return;
  422.     }
  423.     /**
  424.      * @param  string $pre_order_id
  425.      *
  426.      * @return \Eccube\Service\CartService
  427.      */
  428.     public function setPreOrderId($pre_order_id)
  429.     {
  430.         $this->getCart()->setPreOrderId($pre_order_id);
  431.         return $this;
  432.     }
  433.     /**
  434.      * @return string|null
  435.      */
  436.     public function getPreOrderId()
  437.     {
  438.         $Cart $this->getCart();
  439.         if (!empty($Cart)) {
  440.             return $Cart->getPreOrderId();
  441.         }
  442.         return null;
  443.     }
  444.     /**
  445.      * @return \Eccube\Service\CartService
  446.      */
  447.     public function clear()
  448.     {
  449. //log_warning('@@@@ clear');
  450.         $Carts $this->getCarts();
  451.         if (!empty($Carts)) {
  452.             $removed $this->getCart();
  453.             if ($removed && UnitOfWork::STATE_MANAGED === $this->entityManager->getUnitOfWork()->getEntityState($removed)) {
  454. //@##ADD START 2021-11-05 upssek
  455. //log_warning('@@@ CartService.clear');
  456.                 foreach($removed->getCartItems() as $item) {
  457.                     $shelvingOption $item->getShelvingOption();
  458.                     if($shelvingOption != null) {
  459.                         $this->entityManager->remove($shelvingOption);
  460.                         $this->entityManager->flush();
  461.                     }
  462.                     $this->entityManager->remove($item);
  463.                     $this->entityManager->flush();
  464.                 }
  465. //@##ADD END
  466.                 $this->entityManager->remove($removed);
  467.                 $this->entityManager->flush();
  468.                 $cartKeys = [];
  469.                 foreach ($Carts as $key => $Cart) {
  470.                     // テーブルから削除されたカートを除外する
  471.                     if ($Cart == $removed) {
  472.                         unset($Carts[$key]);
  473.                     }
  474.                     $cartKeys[] = $Cart->getCartKey();
  475.                 }
  476.                 $this->session->set('cart_keys'$cartKeys);
  477.                 // 注文完了のカートキーをセッションから削除する
  478.                 $this->session->remove('cart_key');
  479.                 $this->carts $this->cartRepository->findBy(['cart_key' => $cartKeys], ['id' => 'ASC']);
  480.             }
  481.         }
  482.         return $this;
  483.     }
  484.     /**
  485.      * @param CartItemComparator $cartItemComparator
  486.      */
  487.     public function setCartItemComparator($cartItemComparator)
  488.     {
  489.         $this->cartItemComparator $cartItemComparator;
  490.     }
  491.     /**
  492.      * カートキーで指定したインデックスにあるカートを優先にする
  493.      *
  494.      * @param string $cartKey カートキー
  495.      */
  496.     public function setPrimary($cartKey)
  497.     {
  498.         $Carts $this->getCarts();
  499.         $primary $Carts[0];
  500.         $index 0;
  501.         foreach ($Carts as $key => $Cart) {
  502.             if ($Cart->getCartKey() === $cartKey) {
  503.                 $index $key;
  504.                 $primary $Carts[$index];
  505.                 break;
  506.             }
  507.         }
  508.         $prev $Carts[0];
  509.         array_splice($Carts01, [$primary]);
  510.         array_splice($Carts$index1, [$prev]);
  511.         $this->carts $Carts;
  512.         $this->save();
  513.     }
  514.     protected function getUser()
  515.     {
  516.         if (null === $token $this->tokenStorage->getToken()) {
  517.             return;
  518.         }
  519.         if (!is_object($user $token->getUser())) {
  520.             // e.g. anonymous authentication
  521.             return;
  522.         }
  523.         return $user;
  524.     }
  525.     /**
  526.      * @param string $allocatedId
  527.      */
  528.     protected function createCartKey($allocatedIdCustomer $Customer null)
  529.     {
  530.         if ($Customer instanceof Customer) {
  531.             return $Customer->getId().'_'.$allocatedId;
  532.         }
  533.         if ($this->session->has('cart_key_prefix')) {
  534.             return $this->session->get('cart_key_prefix').'_'.$allocatedId;
  535.         }
  536.         do {
  537.             $random StringUtil::random(32);
  538.             $cartKey $random.'_'.$allocatedId;
  539.             $Cart $this->cartRepository->findOneBy(['cart_key' => $cartKey]);
  540.         } while ($Cart);
  541.         $this->session->set('cart_key_prefix'$random);
  542.         return $cartKey;
  543.     }
  544. }