src/Eccube/Service/CartService.php line 181

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 $buyflg 0)
  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($buyflg);
  131.         } else {
  132.             $this->carts $this->getSessionCarts($buyflg);
  133.         }
  134.         return $this->carts;
  135.     }
  136.     /**
  137.      * 永続化されたカートを返す
  138.      *
  139.      * @return Cart[]
  140.      */
  141.     public function getPersistedCarts($buyflg 0)
  142.     {
  143.         //$cartItems = $cartRepository->findBy();
  144.         if($buyflg){
  145.             $cond = ['Customer' => $this->getUser(),'buyflg' => 1];
  146.         }else{
  147.             $cond = ['Customer' => $this->getUser(),'buyflg' => 0];
  148.         }
  149.         return $this->cartRepository->findBy($cond);
  150.     }
  151.     /**
  152.      * セッションにあるカートを返す
  153.      *
  154.      * @return Cart[]
  155.      */
  156.     public function getSessionCarts($buyflg 0)
  157.     {
  158.         if($buyflg){
  159.             $cartKeys $this->session->get('buycart_keys', []);
  160.         }else{
  161.             $cartKeys $this->session->get('cart_keys', []);
  162.         }
  163.         
  164.         //dd($cartKeys);
  165.         if (empty($cartKeys)) {
  166.             return [];
  167.         }
  168.         if($buyflg){
  169.             $cond = ['cart_key' => $cartKeys,'buyflg' => 1];
  170.         }else{
  171.             $cond = ['cart_key' => $cartKeys,'buyflg' => 0];
  172.         }
  173.         return $this->cartRepository->findBy($cond, ['id' => 'ASC']);
  174.     }
  175.     /**
  176.      * 会員が保持する永続化されたカートと、非会員時のカートをマージする.
  177.      */
  178.     public function mergeFromPersistedCart($buyflg=$login=0)
  179.     {
  180.         $persistedCarts $this->getPersistedCarts($buyflg);
  181.         $sessionCarts $this->getSessionCarts($buyflg);
  182.         $CartItems = [];
  183.         // 永続化されたカートとセッションのカートが同一の場合はマージしない #4574
  184.         
  185.         if($buyflg){
  186.             $cartKeys $this->session->get('buycart_keys', []);
  187.         }else{
  188.             $cartKeys $this->session->get('cart_keys', []);
  189.         }
  190.         if ((count($persistedCarts) > 0) && !in_array($persistedCarts[0]->getCartKey(), $cartKeystrue)) {
  191.             foreach ($persistedCarts as $Cart) {
  192.                 $CartItems $this->mergeCartItems($Cart->getCartItems(), $CartItems);
  193.             }
  194.         }
  195.         // セッションにある非会員カートとDBから取得した会員カートをマージする.
  196.         foreach ($sessionCarts as $Cart) {
  197.             $CartItems $this->mergeCartItems($Cart->getCartItems(), $CartItems);
  198.         }
  199.         if($login){
  200.             // 会員が保持する永続化されたカートと、非会員時のカートをマージする.
  201.             $this->login_marge_restoreCarts($CartItems $buyflg);
  202.         }else{
  203.             $this->restoreCarts($CartItems $buyflg);
  204.         }
  205.     }
  206.     /**
  207.      * @return Cart|null
  208.      */
  209.     public function getCart($buyflg 0)
  210.     {
  211.         $Carts $this->getCarts(false $buyflg);
  212.         if (empty($Carts)) {
  213.             return null;
  214.         }
  215.         
  216.         if($buyflg){
  217.             $cartKeys $this->session->get('buycart_keys', []);
  218.         }else{
  219.             $cartKeys $this->session->get('cart_keys', []);
  220.         }
  221.         $Cart null;
  222.         if (count($cartKeys) > 0) {
  223.             foreach ($Carts as $cart) {
  224.                 if ($cart->getCartKey() === current($cartKeys)) {
  225.                     $Cart $cart;
  226.                     break;
  227.                 }
  228.             }
  229.         } else {
  230.             $Cart $Carts[0];
  231.         }
  232.         return $Cart;
  233.     }
  234.     /**
  235.      * @param CartItem[] $cartItems
  236.      *
  237.      * @return CartItem[]
  238.      */
  239.     protected function mergeAllCartItems($cartItems = [] , $buyflg 0)
  240.     {
  241.         /** @var CartItem[] $allCartItems */
  242.         $allCartItems = [];
  243.         foreach ($this->getCarts(false $buyflg) as $Cart) {
  244.             $allCartItems $this->mergeCartItems($Cart->getCartItems(), $allCartItems);
  245.         }
  246.         return $this->mergeCartItems($cartItems$allCartItems);
  247.     }
  248.     /**
  249.      * @param $cartItems
  250.      * @param $allCartItems
  251.      *
  252.      * @return array
  253.      */
  254.     protected function mergeCartItems($cartItems$allCartItems)
  255.     {
  256.         foreach ($cartItems as $item) {
  257.             $itemExists false;
  258.             foreach ($allCartItems as $itemInArray) {
  259.                 // 同じ明細があればマージする
  260.                 if ($this->cartItemComparator->compare($item$itemInArray)) {
  261.                     $itemInArray->setQuantity($itemInArray->getQuantity() + $item->getQuantity());
  262.                     $itemExists true;
  263.                     break;
  264.                 }
  265.             }
  266.             if (!$itemExists) {
  267.                 $allCartItems[] = $item;
  268.             }
  269.         }
  270.         return $allCartItems;
  271.     }
  272.     // 会員が保持する永続化されたカートと、非会員時のカートをマージする.
  273.     //ログイン時限定
  274.     protected function login_marge_restoreCarts($cartItems $buyflg 0)
  275.     {
  276.         foreach ($this->getCarts(false $buyflg) as $Cart) {
  277.             foreach ($Cart->getCartItems() as $i) {
  278.                 //$this->entityManager->remove($i);
  279.                 $this->entityManager->flush();
  280.             }
  281.             //$this->entityManager->remove($Cart);
  282.             $this->entityManager->flush();
  283.         }
  284.         $this->carts = [];
  285.         /** @var Cart[] $Carts */
  286.         $Carts = [];
  287.         foreach ($cartItems as $item) {
  288.             $allocatedId $this->cartItemAllocator->allocate($item);
  289.             $cartKey $this->createCartKey($allocatedId$this->getUser());
  290.             if($buyflg){
  291.                 $cartKey .= "_buy";
  292.             }
  293.             if (isset($Carts[$cartKey])) {
  294.                 $Cart $Carts[$cartKey];
  295.                 $Cart->addCartItem($item);
  296.                 $item->setCart($Cart);
  297.             } else {
  298.                 /** @var Cart $Cart */
  299.                 $Cart $this->cartRepository->findOneBy(['cart_key' => $cartKey 'buyflg'=>$buyflg]);
  300.                 if ($Cart) {
  301.                     foreach ($Cart->getCartItems() as $i) {
  302.                         //$this->entityManager->remove($i);
  303.                         $this->entityManager->flush();
  304.                     }
  305.                     //$this->entityManager->remove($Cart);
  306.                     $this->entityManager->flush();
  307.                 }
  308.                 $Cart = new Cart();
  309.                 $Cart->setCartKey($cartKey);
  310.                 $Cart->addCartItem($item);
  311.                 $item->setCart($Cart);
  312.                 $Carts[$cartKey] = $Cart;
  313.                 
  314.             }
  315.         }
  316.         $this->carts array_values($Carts);
  317.     }
  318.     protected function restoreCarts($cartItems $buyflg 0)
  319.     {
  320.         foreach ($this->getCarts(false $buyflg) as $Cart) {
  321.             foreach ($Cart->getCartItems() as $i) {
  322.                 $this->entityManager->remove($i);
  323.                 $this->entityManager->flush();
  324.             }
  325.             $this->entityManager->remove($Cart);
  326.             $this->entityManager->flush();
  327.         }
  328.         $this->carts = [];
  329.         /** @var Cart[] $Carts */
  330.         $Carts = [];
  331.         foreach ($cartItems as $item) {
  332.             $allocatedId $this->cartItemAllocator->allocate($item);
  333.             $cartKey $this->createCartKey($allocatedId$this->getUser());
  334.             if($buyflg){
  335.                 $cartKey .= "_buy";
  336.             }
  337.             if (isset($Carts[$cartKey])) {
  338.                 $Cart $Carts[$cartKey];
  339.                 $Cart->addCartItem($item);
  340.                 $item->setCart($Cart);
  341.             } else {
  342.                 /** @var Cart $Cart */
  343.                 $Cart $this->cartRepository->findOneBy(['cart_key' => $cartKey 'buyflg'=>$buyflg]);
  344.                 if ($Cart) {
  345.                     foreach ($Cart->getCartItems() as $i) {
  346.                         //$this->entityManager->remove($i);
  347.                         $this->entityManager->flush();
  348.                     }
  349.                     //$this->entityManager->remove($Cart);
  350.                     $this->entityManager->flush();
  351.                 }
  352.                 $Cart = new Cart();
  353.                 $Cart->setCartKey($cartKey);
  354.                 $Cart->addCartItem($item);
  355.                 $item->setCart($Cart);
  356.                 $Carts[$cartKey] = $Cart;
  357.                 
  358.             }
  359.         }
  360.         $this->carts array_values($Carts);
  361.     }
  362.     /**
  363.      * カートに商品を追加します.
  364.      *
  365.      * @param $ProductClass ProductClass 商品規格
  366.      * @param $quantity int 数量
  367.      *
  368.      * @return bool 商品を追加できた場合はtrue
  369.      */
  370.     public function addProduct($ProductClass$quantity $buyflg=0)
  371.     {
  372.         if (!$ProductClass instanceof ProductClass) {
  373.             $ProductClassId $ProductClass;
  374.             $ProductClass $this->entityManager
  375.                 ->getRepository(ProductClass::class)
  376.                 ->find($ProductClassId);
  377.             if (is_null($ProductClass)) {
  378.                 return false;
  379.             }
  380.         }
  381.         $ClassCategory1 $ProductClass->getClassCategory1();
  382.         if ($ClassCategory1 && !$ClassCategory1->isVisible()) {
  383.             return false;
  384.         }
  385.         $ClassCategory2 $ProductClass->getClassCategory2();
  386.         if ($ClassCategory2 && !$ClassCategory2->isVisible()) {
  387.             return false;
  388.         }
  389.         $newItem = new CartItem();
  390.         $newItem->setQuantity($quantity);
  391.         $newItem->setPrice($ProductClass->getPrice02IncTax());
  392.         $newItem->setProductClass($ProductClass);
  393.         $allCartItems $this->mergeAllCartItems([$newItem] , $buyflg);
  394.         $this->restoreCarts($allCartItems $buyflg);
  395.         return true;
  396.     }
  397.     public function removeProduct($ProductClass $buyflg=0)
  398.     {
  399.         if (!$ProductClass instanceof ProductClass) {
  400.             $ProductClassId $ProductClass;
  401.             $ProductClass $this->entityManager
  402.                 ->getRepository(ProductClass::class)
  403.                 ->find($ProductClassId);
  404.             if (is_null($ProductClass)) {
  405.                 return false;
  406.             }
  407.         }
  408.         $removeItem = new CartItem();
  409.         $removeItem->setPrice($ProductClass->getPrice02IncTax());
  410.         $removeItem->setProductClass($ProductClass);
  411.         $allCartItems $this->mergeAllCartItems([],$buyflg);
  412.         $foundIndex = -1;
  413.         foreach ($allCartItems as $index => $itemInCart) {
  414.             if ($this->cartItemComparator->compare($itemInCart$removeItem)) {
  415.                 $foundIndex $index;
  416.                 break;
  417.             }
  418.         }
  419.         array_splice($allCartItems$foundIndex1);
  420.         $this->restoreCarts($allCartItems,$buyflg);
  421.         return true;
  422.     }
  423.     public function save($buyflg=0)
  424.     {
  425.         $cartKeys = [];
  426.         foreach ($this->carts as $Cart) {
  427.             $Cart->setCustomer($this->getUser());
  428.             if($buyflg){
  429.                 $Cart->setBuyflg("1");
  430.             }else{
  431.                 $Cart->setBuyflg("0");
  432.             }
  433.             $this->entityManager->persist($Cart);
  434.             foreach ($Cart->getCartItems() as $item) {
  435.                 $this->entityManager->persist($item);
  436.             }
  437.             $this->entityManager->flush();
  438.             $cartKeys[] = $Cart->getCartKey();
  439.             if($buyflg){
  440.                 $this->session->set('buycart_keys'$cartKeys);
  441.             }else{
  442.                 $this->session->set('cart_keys'$cartKeys);
  443.             }
  444.         }
  445.         return;
  446.     }
  447.     /**
  448.      * @param  string $pre_order_id
  449.      *
  450.      * @return \Eccube\Service\CartService
  451.      */
  452.     public function setPreOrderId($pre_order_id)
  453.     {
  454.         $this->getCart()->setPreOrderId($pre_order_id);
  455.         return $this;
  456.     }
  457.     /**
  458.      * @return string|null
  459.      */
  460.     public function getPreOrderId($buyflg=0)
  461.     {
  462.         $Cart $this->getCart($buyflg);
  463.         if (!empty($Cart)) {
  464.             return $Cart->getPreOrderId();
  465.         }
  466.         return null;
  467.     }
  468.     /**
  469.      * @return \Eccube\Service\CartService
  470.      */
  471.     public function clear($buyflg=0)
  472.     {
  473.         $Carts $this->getCarts(false $buyflg);
  474.         if (!empty($Carts)) {
  475.             $removed $this->getCart(false $buyflg);
  476.             if ($removed && UnitOfWork::STATE_MANAGED === $this->entityManager->getUnitOfWork()->getEntityState($removed)) {
  477.                 $this->entityManager->remove($removed);
  478.                 $this->entityManager->flush();
  479.                 $cartKeys = [];
  480.                 foreach ($Carts as $key => $Cart) {
  481.                     // テーブルから削除されたカートを除外する
  482.                     if ($Cart == $removed) {
  483.                         unset($Carts[$key]);
  484.                     }
  485.                     $cartKeys[] = $Cart->getCartKey();
  486.                     if($buyflg){
  487.                         $this->session->set('buycart_keys'$cartKeys);
  488.                         // 注文完了のカートキーをセッションから削除する
  489.                         $this->session->remove('buycart_key');
  490.                     }else{
  491.                         $this->session->set('cart_keys'$cartKeys);
  492.                         // 注文完了のカートキーをセッションから削除する
  493.                         $this->session->remove('cart_key');
  494.                     }
  495.                 }
  496.                 
  497.                 
  498.                 if($buyflg){
  499.                     $cond = ['cart_key' => $cartKeys,'buyflg' => 1];
  500.                 }else{
  501.                     $cond = ['cart_key' => $cartKeys,'buyflg' => 0];
  502.                 }
  503.                 $this->carts $this->cartRepository->findBy($cond, ['id' => 'ASC']);
  504.             }
  505.         }
  506.         return $this;
  507.     }
  508.     /**
  509.      * @param CartItemComparator $cartItemComparator
  510.      */
  511.     public function setCartItemComparator($cartItemComparator)
  512.     {
  513.         $this->cartItemComparator $cartItemComparator;
  514.     }
  515.     /**
  516.      * カートキーで指定したインデックスにあるカートを優先にする
  517.      *
  518.      * @param string $cartKey カートキー
  519.      */
  520.     public function setPrimary($cartKey $buyflg=0)
  521.     {
  522.         $Carts $this->getCarts(false $buyflg);
  523.         $primary $Carts[0];
  524.         $index 0;
  525.         foreach ($Carts as $key => $Cart) {
  526.             if ($Cart->getCartKey() === $cartKey) {
  527.                 $index $key;
  528.                 $primary $Carts[$index];
  529.                 break;
  530.             }
  531.         }
  532.         $prev $Carts[0];
  533.         array_splice($Carts01, [$primary]);
  534.         array_splice($Carts$index1, [$prev]);
  535.         $this->carts $Carts;
  536.         $this->save($buyflg);
  537.     }
  538.     protected function getUser()
  539.     {
  540.         if (null === $token $this->tokenStorage->getToken()) {
  541.             return;
  542.         }
  543.         if (!is_object($user $token->getUser())) {
  544.             // e.g. anonymous authentication
  545.             return;
  546.         }
  547.         return $user;
  548.     }
  549.     /**
  550.      * @param string $allocatedId
  551.      */
  552.     protected function createCartKey($allocatedIdCustomer $Customer null)
  553.     {
  554.         if ($Customer instanceof Customer) {
  555.             return $Customer->getId().'_'.$allocatedId;
  556.         }
  557.         if ($this->session->has('cart_key_prefix')) {
  558.             return $this->session->get('cart_key_prefix').'_'.$allocatedId;
  559.         }
  560.         do {
  561.             $random StringUtil::random(32);
  562.             $cartKey $random.'_'.$allocatedId;
  563.             $Cart $this->cartRepository->findOneBy(['cart_key' => $cartKey]);
  564.         } while ($Cart);
  565.         $this->session->set('cart_key_prefix'$random);
  566.         return $cartKey;
  567.     }
  568. }