src/Eccube/Service/CartService.php line 188

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