src/Eccube/Service/CartService.php line 148

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 Symfony\Component\HttpFoundation\Session\SessionInterface;
  27. use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
  28. use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
  29. //商品価格カスタム用(ゲスト価格と会員価格の分岐)
  30. use Customize\Service\CustomPriceService;
  31. class CartService
  32. {
  33.     /**
  34.      * @var Cart[]
  35.      */
  36.     protected $carts;
  37.     /**
  38.      * @var SessionInterface
  39.      */
  40.     protected $session;
  41.     /**
  42.      * @var \Doctrine\ORM\EntityManagerInterface
  43.      */
  44.     protected $entityManager;
  45.     /**
  46.      * @var ItemHolderInterface
  47.      *
  48.      * @deprecated
  49.      */
  50.     protected $cart;
  51.     /**
  52.      * @var ProductClassRepository
  53.      */
  54.     protected $productClassRepository;
  55.     /**
  56.      * @var CartRepository
  57.      */
  58.     protected $cartRepository;
  59.     /**
  60.      * @var CartItemComparator
  61.      */
  62.     protected $cartItemComparator;
  63.     /**
  64.      * @var CartItemAllocator
  65.      */
  66.     protected $cartItemAllocator;
  67.     /**
  68.      * @var OrderRepository
  69.      */
  70.     protected $orderRepository;
  71.     /**
  72.      * @var TokenStorageInterface
  73.      */
  74.     protected $tokenStorage;
  75.     /**
  76.      * @var AuthorizationCheckerInterface
  77.      */
  78.     protected $authorizationChecker;
  79.     /**
  80.      * CartService constructor.
  81.      */
  82.     private $customPriceService;
  83.     public function __construct(
  84.         SessionInterface $session,
  85.         EntityManagerInterface $entityManager,
  86.         ProductClassRepository $productClassRepository,
  87.         CartRepository $cartRepository,
  88.         CartItemComparator $cartItemComparator,
  89.         CartItemAllocator $cartItemAllocator,
  90.         OrderRepository $orderRepository,
  91.         TokenStorageInterface $tokenStorage,
  92.         AuthorizationCheckerInterface $authorizationChecker,
  93.         CustomPriceService $customPriceService  // 追加する依存関係
  94.     ) {
  95.         $this->session $session;
  96.         $this->entityManager $entityManager;
  97.         $this->productClassRepository $productClassRepository;
  98.         $this->cartRepository $cartRepository;
  99.         $this->cartItemComparator $cartItemComparator;
  100.         $this->cartItemAllocator $cartItemAllocator;
  101.         $this->orderRepository $orderRepository;
  102.         $this->tokenStorage $tokenStorage;
  103.         $this->authorizationChecker $authorizationChecker;
  104.         $this->customPriceService $customPriceService;
  105.     }
  106.     /**
  107.      * 現在のカートの配列を取得する.
  108.      *
  109.      * 本サービスのインスタンスのメンバーが空の場合は、DBまたはセッションからカートを取得する
  110.      *
  111.      * @param bool $empty_delete true の場合、商品明細が空のカートが存在した場合は削除する
  112.      *
  113.      * @return Cart[]
  114.      */
  115.     public function getCarts($empty_delete false)
  116.     {
  117.         if (null !== $this->carts) {
  118.             if ($empty_delete) {
  119.                 $cartKeys = [];
  120.                 foreach (array_keys($this->carts) as $index) {
  121.                     $Cart $this->carts[$index];
  122.                     if ($Cart->getItems()->count() > 0) {
  123.                         $cartKeys[] = $Cart->getCartKey();
  124.                     } else {
  125.                         $this->entityManager->remove($this->carts[$index]);
  126.                         $this->entityManager->flush();
  127.                         unset($this->carts[$index]);
  128.                     }
  129.                 }
  130.                 $this->session->set('cart_keys'$cartKeys);
  131.             }
  132.             return $this->carts;
  133.         }
  134.         if ($this->getUser()) {
  135.             $this->carts $this->getPersistedCarts();
  136.         } else {
  137.             $this->carts $this->getSessionCarts();
  138.         }
  139.         return $this->carts;
  140.     }
  141.     /**
  142.      * 永続化されたカートを返す
  143.      *
  144.      * @return Cart[]
  145.      */
  146.     public function getPersistedCarts()
  147.     {
  148.         return $this->cartRepository->findBy(['Customer' => $this->getUser()]);
  149.     }
  150.     /**
  151.      * セッションにあるカートを返す
  152.      *
  153.      * @return Cart[]
  154.      */
  155.     public function getSessionCarts()
  156.     {
  157.         $cartKeys $this->session->get('cart_keys', []);
  158.         if (empty($cartKeys)) {
  159.             return [];
  160.         }
  161.         return $this->cartRepository->findBy(['cart_key' => $cartKeys], ['id' => 'ASC']);
  162.     }
  163.     /**
  164.      * 会員が保持する永続化されたカートと、非会員時のカートをマージする.
  165.      */
  166.     public function mergeFromPersistedCart()
  167.     {
  168.         $persistedCarts $this->getPersistedCarts();
  169.         $sessionCarts $this->getSessionCarts();
  170.         $CartItems = [];
  171.         // 永続化されたカートとセッションのカートが同一の場合はマージしない #4574
  172.         $cartKeys $this->session->get('cart_keys', []);
  173.         if ((count($persistedCarts) > 0) && !in_array($persistedCarts[0]->getCartKey(), $cartKeystrue)) {
  174.             foreach ($persistedCarts as $Cart) {
  175.                 $CartItems $this->mergeCartItems($Cart->getCartItems(), $CartItems);
  176.             }
  177.         }
  178.         // セッションにある非会員カートとDBから取得した会員カートをマージする.
  179.         foreach ($sessionCarts as $Cart) {
  180.             $CartItems $this->mergeCartItems($Cart->getCartItems(), $CartItems);
  181.         }
  182.         $this->restoreCarts($CartItems);
  183.     }
  184.     /**
  185.      * @return Cart|null
  186.      */
  187.     public function getCart()
  188.     {
  189.         $Carts $this->getCarts();
  190.         if (empty($Carts)) {
  191.             return null;
  192.         }
  193.         $cartKeys $this->session->get('cart_keys', []);
  194.         $Cart null;
  195.         if (count($cartKeys) > 0) {
  196.             foreach ($Carts as $cart) {
  197.                 if ($cart->getCartKey() === current($cartKeys)) {
  198.                     $Cart $cart;
  199.                     break;
  200.                 }
  201.             }
  202.         } else {
  203.             $Cart $Carts[0];
  204.         }
  205.         return $Cart;
  206.     }
  207.     /**
  208.      * @param CartItem[] $cartItems
  209.      *
  210.      * @return CartItem[]
  211.      */
  212.     protected function mergeAllCartItems($cartItems = [])
  213.     {
  214.         /** @var CartItem[] $allCartItems */
  215.         $allCartItems = [];
  216.         foreach ($this->getCarts() as $Cart) {
  217.             $allCartItems $this->mergeCartItems($Cart->getCartItems(), $allCartItems);
  218.         }
  219.         return $this->mergeCartItems($cartItems$allCartItems);
  220.     }
  221.     /**
  222.      * @param $cartItems
  223.      * @param $allCartItems
  224.      *
  225.      * @return array
  226.      */
  227.     protected function mergeCartItems($cartItems$allCartItems)
  228.     {
  229.         foreach ($cartItems as $item) {
  230.             $itemExists false;
  231.             foreach ($allCartItems as $itemInArray) {
  232.                 // 同じ明細があればマージする
  233.                 if ($this->cartItemComparator->compare($item$itemInArray)) {
  234.                     $itemInArray->setQuantity($itemInArray->getQuantity() + $item->getQuantity());
  235.                     $itemExists true;
  236.                     break;
  237.                 }
  238.             }
  239.             if (!$itemExists) {
  240.                 $allCartItems[] = $item;
  241.             }
  242.         }
  243.         return $allCartItems;
  244.     }
  245.     protected function restoreCarts($cartItems)
  246.     {
  247.         foreach ($this->getCarts() as $Cart) {
  248.             foreach ($Cart->getCartItems() as $i) {
  249.                 $this->entityManager->remove($i);
  250.                 $this->entityManager->flush();
  251.             }
  252.             $this->entityManager->remove($Cart);
  253.             $this->entityManager->flush();
  254.         }
  255.         $this->carts = [];
  256.         /** @var Cart[] $Carts */
  257.         $Carts = [];
  258.         foreach ($cartItems as $item) {
  259.             $allocatedId $this->cartItemAllocator->allocate($item);
  260.             $cartKey $this->createCartKey($allocatedId$this->getUser());
  261.             if (isset($Carts[$cartKey])) {
  262.                 $Cart $Carts[$cartKey];
  263.                 $Cart->addCartItem($item);
  264.                 $item->setCart($Cart);
  265.             } else {
  266.                 /** @var Cart $Cart */
  267.                 $Cart $this->cartRepository->findOneBy(['cart_key' => $cartKey]);
  268.                 if ($Cart) {
  269.                     foreach ($Cart->getCartItems() as $i) {
  270.                         $this->entityManager->remove($i);
  271.                         $this->entityManager->flush();
  272.                     }
  273.                     $this->entityManager->remove($Cart);
  274.                     $this->entityManager->flush();
  275.                 }
  276.                 $Cart = new Cart();
  277.                 $Cart->setCartKey($cartKey);
  278.                 $Cart->addCartItem($item);
  279.                 $item->setCart($Cart);
  280.                 $Carts[$cartKey] = $Cart;
  281.             }
  282.         }
  283.         $this->carts array_values($Carts);
  284.     }
  285.     /**
  286.      * カートに商品を追加します.
  287.      *
  288.      * @param $ProductClass ProductClass 商品規格
  289.      * @param $quantity int 数量
  290.      *
  291.      * @return bool 商品を追加できた場合はtrue
  292.      */
  293.     public function addProduct($ProductClass$quantity 1)
  294.     {
  295.         if (!$ProductClass instanceof ProductClass) {
  296.             $ProductClassId $ProductClass;
  297.             $ProductClass $this->entityManager
  298.                 ->getRepository(ProductClass::class)
  299.                 ->find($ProductClassId);
  300.             if (is_null($ProductClass)) {
  301.                 return false;
  302.             }
  303.         }
  304.         $ClassCategory1 $ProductClass->getClassCategory1();
  305.         if ($ClassCategory1 && !$ClassCategory1->isVisible()) {
  306.             return false;
  307.         }
  308.         $ClassCategory2 $ProductClass->getClassCategory2();
  309.         if ($ClassCategory2 && !$ClassCategory2->isVisible()) {
  310.             return false;
  311.         }
  312.         $newItem = new CartItem();
  313.         $newItem->setQuantity($quantity);
  314.         $newItem->setPrice($ProductClass->getPrice02IncTax());
  315.         // カスタム料金を取得して設定
  316.         // $customPrice = $this->customPriceService->getCustomPriceIncTax($ProductClass);
  317.         // $newItem->setPrice($customPrice);
  318.         $newItem->setProductClass($ProductClass);
  319.         $allCartItems $this->mergeAllCartItems([$newItem]);
  320.         $this->restoreCarts($allCartItems);
  321.         return true;
  322.     }
  323.     public function removeProduct($ProductClass)
  324.     {
  325.         if (!$ProductClass instanceof ProductClass) {
  326.             $ProductClassId $ProductClass;
  327.             $ProductClass $this->entityManager
  328.                 ->getRepository(ProductClass::class)
  329.                 ->find($ProductClassId);
  330.             if (is_null($ProductClass)) {
  331.                 return false;
  332.             }
  333.         }
  334.         $removeItem = new CartItem();
  335.         $removeItem->setPrice($ProductClass->getPrice02IncTax());
  336.         // $customPrice = $this->customPriceService->getCustomPriceIncTax($ProductClass);
  337.         $removeItem->setProductClass($ProductClass);
  338.         $allCartItems $this->mergeAllCartItems();
  339.         $foundIndex = -1;
  340.         foreach ($allCartItems as $index => $itemInCart) {
  341.             if ($this->cartItemComparator->compare($itemInCart$removeItem)) {
  342.                 $foundIndex $index;
  343.                 break;
  344.             }
  345.         }
  346.         array_splice($allCartItems$foundIndex1);
  347.         $this->restoreCarts($allCartItems);
  348.         return true;
  349.     }
  350.     public function save()
  351.     {
  352.         $cartKeys = [];
  353.         foreach ($this->carts as $Cart) {
  354.             $Cart->setCustomer($this->getUser());
  355.             $this->entityManager->persist($Cart);
  356.             foreach ($Cart->getCartItems() as $item) {
  357.                 $this->entityManager->persist($item);
  358.             }
  359.             $this->entityManager->flush();
  360.             $cartKeys[] = $Cart->getCartKey();
  361.         }
  362.         $this->session->set('cart_keys'$cartKeys);
  363.         return;
  364.     }
  365.     /**
  366.      * @param  string $pre_order_id
  367.      *
  368.      * @return \Eccube\Service\CartService
  369.      */
  370.     public function setPreOrderId($pre_order_id)
  371.     {
  372.         $this->getCart()->setPreOrderId($pre_order_id);
  373.         return $this;
  374.     }
  375.     /**
  376.      * @return string|null
  377.      */
  378.     public function getPreOrderId()
  379.     {
  380.         $Cart $this->getCart();
  381.         if (!empty($Cart)) {
  382.             return $Cart->getPreOrderId();
  383.         }
  384.         return null;
  385.     }
  386.     /**
  387.      * @return \Eccube\Service\CartService
  388.      */
  389.     public function clear()
  390.     {
  391.         $Carts $this->getCarts();
  392.         if (!empty($Carts)) {
  393.             $removed $this->getCart();
  394.             if ($removed && UnitOfWork::STATE_MANAGED === $this->entityManager->getUnitOfWork()->getEntityState($removed)) {
  395.                 $this->entityManager->remove($removed);
  396.                 $this->entityManager->flush();
  397.                 $cartKeys = [];
  398.                 foreach ($Carts as $key => $Cart) {
  399.                     // テーブルから削除されたカートを除外する
  400.                     if ($Cart == $removed) {
  401.                         unset($Carts[$key]);
  402.                     }
  403.                     $cartKeys[] = $Cart->getCartKey();
  404.                 }
  405.                 $this->session->set('cart_keys'$cartKeys);
  406.                 // 注文完了のカートキーをセッションから削除する
  407.                 $this->session->remove('cart_key');
  408.                 $this->carts $this->cartRepository->findBy(['cart_key' => $cartKeys], ['id' => 'ASC']);
  409.             }
  410.         }
  411.         return $this;
  412.     }
  413.     /**
  414.      * @param CartItemComparator $cartItemComparator
  415.      */
  416.     public function setCartItemComparator($cartItemComparator)
  417.     {
  418.         $this->cartItemComparator $cartItemComparator;
  419.     }
  420.     /**
  421.      * カートキーで指定したインデックスにあるカートを優先にする
  422.      *
  423.      * @param string $cartKey カートキー
  424.      */
  425.     public function setPrimary($cartKey)
  426.     {
  427.         $Carts $this->getCarts();
  428.         $primary $Carts[0];
  429.         $index 0;
  430.         foreach ($Carts as $key => $Cart) {
  431.             if ($Cart->getCartKey() === $cartKey) {
  432.                 $index $key;
  433.                 $primary $Carts[$index];
  434.                 break;
  435.             }
  436.         }
  437.         $prev $Carts[0];
  438.         array_splice($Carts01, [$primary]);
  439.         array_splice($Carts$index1, [$prev]);
  440.         $this->carts $Carts;
  441.         $this->save();
  442.     }
  443.     protected function getUser()
  444.     {
  445.         if (null === $token $this->tokenStorage->getToken()) {
  446.             return;
  447.         }
  448.         if (!is_object($user $token->getUser())) {
  449.             // e.g. anonymous authentication
  450.             return;
  451.         }
  452.         return $user;
  453.     }
  454.     /**
  455.      * @param string $allocatedId
  456.      */
  457.     protected function createCartKey($allocatedIdCustomer $Customer null)
  458.     {
  459.         if ($Customer instanceof Customer) {
  460.             return $Customer->getId().'_'.$allocatedId;
  461.         }
  462.         if ($this->session->has('cart_key_prefix')) {
  463.             return $this->session->get('cart_key_prefix').'_'.$allocatedId;
  464.         }
  465.         do {
  466.             $random StringUtil::random(32);
  467.             $cartKey $random.'_'.$allocatedId;
  468.             $Cart $this->cartRepository->findOneBy(['cart_key' => $cartKey]);
  469.         } while ($Cart);
  470.         $this->session->set('cart_key_prefix'$random);
  471.         return $cartKey;
  472.     }
  473. }