src/Eccube/Service/CartService.php line 492

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