app/Customize/Service/CartService.php line 143

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