app/Customize/Service/EstimateCartService.php line 170

Open in your IDE?
  1. <?php
  2. namespace Customize\Service;
  3. use Customize\Entity\EstimateCart;
  4. use Customize\Entity\EstimateCartItem;
  5. use Customize\Entity\Master\EstimateItemType;
  6. use Customize\Repository\EstimateCartRepository;
  7. use Customize\Repository\EstimateRepository;
  8. use Customize\Repository\Master\EstimateItemTypeRepository;
  9. use Doctrine\ORM\EntityManagerInterface;
  10. use Doctrine\ORM\UnitOfWork;
  11. use Eccube\Entity\Cart;
  12. use Eccube\Entity\CartItem;
  13. use Eccube\Entity\Customer;
  14. use Eccube\Entity\ItemHolderInterface;
  15. use Eccube\Entity\ProductClass;
  16. use Eccube\Repository\ProductClassRepository;
  17. use Eccube\Service\Cart\CartItemAllocator;
  18. use Eccube\Service\Cart\CartItemComparator;
  19. use Eccube\Util\StringUtil;
  20. use Plugin\ProductOption42\Service\Cart\ProductClassAndOptionComparator;
  21. use Symfony\Component\HttpFoundation\Session\SessionInterface;
  22. use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
  23. use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
  24. class EstimateCartService
  25. {
  26.     /**
  27.      * @var EstimateCart[]
  28.      */
  29.     protected $estimateCarts;
  30.     /**
  31.      * @var SessionInterface
  32.      */
  33.     protected $session;
  34.     /**
  35.      * @var \Doctrine\ORM\EntityManagerInterface
  36.      */
  37.     protected $entityManager;
  38.     /**
  39.      * @var ItemHolderInterface
  40.      *
  41.      * @deprecated
  42.      */
  43.     protected $estimateCart;
  44.     /**
  45.      * @var ProductClassRepository
  46.      */
  47.     protected $productClassRepository;
  48.     /**
  49.      * @var EstimateCartRepository
  50.      */
  51.     protected $EstimateCartRepository;
  52.     /**
  53.      * @var ProductClassAndOptionComparator
  54.      */
  55.     protected $productClassAndOptionComparator;
  56.     /**
  57.      * @var EstimateRepository
  58.      */
  59.     protected $estimateRepository;
  60.     /**
  61.      * @var TokenStorageInterface
  62.      */
  63.     protected $tokenStorage;
  64.     /**
  65.      * @var AuthorizationCheckerInterface
  66.      */
  67.     protected $authorizationChecker;
  68.     /**
  69.      * @var EstimateItemTypeRepository
  70.      */
  71.     protected $estimateItemTypeRepository;
  72.     /**
  73.      * EstimateCartService constructor.
  74.      */
  75.     public function __construct(
  76.         SessionInterface $session,
  77.         EntityManagerInterface $entityManager,
  78.         ProductClassRepository $productClassRepository,
  79.         EstimateCartRepository $estimateCartRepository,
  80.         ProductClassAndOptionComparator $productClassAndOptionComparator,
  81.         CartItemAllocator $cartItemAllocator,
  82.         EstimateRepository $estimateRepository,
  83.         TokenStorageInterface $tokenStorage,
  84.         AuthorizationCheckerInterface $authorizationChecker,
  85.         EstimateItemTypeRepository $estimateItemTypeRepository
  86.     ) {
  87.         $this->session = $session;
  88.         $this->entityManager = $entityManager;
  89.         $this->productClassRepository = $productClassRepository;
  90.         $this->estimateCartRepository = $estimateCartRepository;
  91.         $this->productClassAndOptionComparator = $productClassAndOptionComparator;
  92.         $this->cartItemAllocator = $cartItemAllocator;
  93.         $this->estimateRepository = $estimateRepository;
  94.         $this->tokenStorage = $tokenStorage;
  95.         $this->authorizationChecker = $authorizationChecker;
  96.         $this->estimateItemTypeRepository = $estimateItemTypeRepository;
  97.     }
  98.     /**
  99.      * 現在のカートの配列を取得する.
  100.      *
  101.      * 本サービスのインスタンスのメンバーが空の場合は、DBまたはセッションからカートを取得する
  102.      *
  103.      * @param bool $empty_delete true の場合、商品明細が空のカートが存在した場合は削除する
  104.      *
  105.      * @return EstimateCart[]
  106.      */
  107.     public function getCarts($empty_delete = false)
  108.     {
  109.         if (null !== $this->estimateCarts) {
  110.             if ($empty_delete) {
  111.                 $cartKeys = [];
  112.                 foreach (array_keys($this->estimateCarts) as $index) {
  113.                     $Cart = $this->estimateCarts[$index];
  114.                     if ($Cart->getItems()->count() > 0) {
  115.                         $cartKeys[] = $Cart->getCartKey();
  116.                     } else {
  117.                         $this->entityManager->remove($this->estimateCarts[$index]);
  118.                         $this->entityManager->flush();
  119.                         unset($this->estimateCarts[$index]);
  120.                     }
  121.                 }
  122.                 $this->session->set('estimate_cart_keys', $cartKeys);
  123.             }
  124.             return $this->estimateCarts;
  125.         }
  126.         if ($this->getUser()) {
  127.             $this->estimateCarts = $this->getPersistedCarts();
  128.         } else {
  129.             $this->estimateCarts = $this->getSessionCarts();
  130.         }
  131.         return $this->estimateCarts;
  132.     }
  133.     /**
  134.      * 永続化されたカートを返す
  135.      *
  136.      * @return Cart[]
  137.      */
  138.     public function getPersistedCarts()
  139.     {
  140.         return $this->estimateCartRepository->findBy(['Customer' => $this->getUser()]);
  141.     }
  142.     /**
  143.      * セッションにあるカートを返す
  144.      *
  145.      * @return Cart[]
  146.      */
  147.     public function getSessionCarts()
  148.     {
  149.         $cartKeys = $this->session->get('estimate_cart_keys', []);
  150.         if (empty($cartKeys)) {
  151.             return [];
  152.         }
  153.         return $this->estimateCartRepository->findBy(['cart_key' => $cartKeys], ['id' => 'ASC']);
  154.     }
  155.     /**
  156.      * 会員が保持する永続化されたカートと、非会員時のカートをマージする.
  157.      */
  158.     public function mergeFromPersistedCart()
  159.     {
  160.         $persistedCarts = $this->getPersistedCarts();
  161.         $sessionCarts = $this->getSessionCarts();
  162.         $CartItems = [];
  163.         // 永続化されたカートとセッションのカートが同一の場合はマージしない #4574
  164.         $cartKeys = $this->session->get('estimate_cart_keys', []);
  165.         if ((count($persistedCarts) > 0) && !in_array($persistedCarts[0]->getCartKey(), $cartKeys, true)) {
  166.             foreach ($persistedCarts as $Cart) {
  167.                 $CartItems = $this->mergeCartItems($Cart->getCartItems(), $CartItems);
  168.             }
  169.         }
  170.         // セッションにある非会員カートとDBから取得した会員カートをマージする.
  171.         foreach ($sessionCarts as $Cart) {
  172.             $CartItems = $this->mergeCartItems($Cart->getCartItems(), $CartItems);
  173.         }
  174.         $this->restoreCarts($CartItems);
  175.     }
  176.     /**
  177.      * @return Cart|null
  178.      */
  179.     public function getCart()
  180.     {
  181.         $Carts = $this->getCarts();
  182.         if (empty($Carts)) {
  183.             return null;
  184.         }
  185.         $cartKeys = $this->session->get('estimate_cart_keys', []);
  186.         $Cart = null;
  187.         if (count($cartKeys) > 0) {
  188.             foreach ($Carts as $cart) {
  189.                 if ($cart->getCartKey() === current($cartKeys)) {
  190.                     $Cart = $cart;
  191.                     break;
  192.                 }
  193.             }
  194.         } else {
  195.             $Cart = $Carts[0];
  196.         }
  197.         return $Cart;
  198.     }
  199.     /**
  200.      * @param EstimateCartItem[] $cartItems
  201.      *
  202.      * @return EstimateCartItem[]
  203.      */
  204.     protected function mergeAllCartItems($cartItems = [])
  205.     {
  206.         /** @var EstimateCartItem[] $allCartItems */
  207.         $allCartItems = [];
  208.         foreach ($this->getCarts() as $Cart) {
  209.             $allCartItems = $this->mergeCartItems($Cart->getCartItems(), $allCartItems);
  210.         }
  211.         return $this->mergeCartItems($cartItems, $allCartItems);
  212.     }
  213.     /**
  214.      * @param $cartItems
  215.      * @param $allCartItems
  216.      *
  217.      * @return array
  218.      */
  219.     protected function mergeCartItems($cartItems, $allCartItems)
  220.     {
  221.         foreach ($cartItems as $item) {
  222. //            $itemExists = false;
  223. //            foreach ($allCartItems as $itemInArray) {
  224. //                // 同じ明細があればマージする
  225. //                if ($this->productClassAndOptionComparator->compare2($item, $itemInArray)) {
  226. //                    $itemInArray->setQuantity($itemInArray->getQuantity() + $item->getQuantity());
  227. //                    $itemExists = true;
  228. //                    break;
  229. //                }
  230. //            }
  231. //            if (!$itemExists) {
  232.                 $allCartItems[] = $item;
  233. //            }
  234.         }
  235.         return $allCartItems;
  236.     }
  237.     protected function restoreCarts($cartItems)
  238.     {
  239.         foreach ($this->getCarts() as $Cart) {
  240.             foreach ($Cart->getCartItems() as $i) {
  241.                 $this->entityManager->remove($i);
  242.                 $this->entityManager->flush();
  243.             }
  244.             $this->entityManager->remove($Cart);
  245.             $this->entityManager->flush();
  246.         }
  247.         $this->estimateCarts = [];
  248.         /** @var EstimateCart[] $Carts */
  249.         $Carts = [];
  250.         foreach ( $cartItems as $item ) {
  251.             $allocatedId = $this->allocate($item);
  252.             if ( !empty($allocatedId) ) {
  253.                 break;
  254.             }
  255.         }
  256.         foreach ($cartItems as $item) {
  257.             $cartKey = $this->createCartKey($allocatedId, $this->getUser());
  258.             if (isset($Carts[$cartKey])) {
  259.                 $Cart = $Carts[$cartKey];
  260.                 $Cart->addCartItem($item);
  261.                 $item->setCart($Cart);
  262.             } else {
  263.                 /** @var EstimateCart $Cart */
  264.                 $Cart = $this->estimateCartRepository->findOneBy(['cart_key' => $cartKey]);
  265.                 if ($Cart) {
  266.                     foreach ($Cart->getCartItems() as $i) {
  267.                         $this->entityManager->remove($i);
  268.                         $this->entityManager->flush();
  269.                     }
  270.                     $this->entityManager->remove($Cart);
  271.                     $this->entityManager->flush();
  272.                 }
  273.                 $Cart = new EstimateCart();
  274.                 $Cart->setCartKey($cartKey);
  275.                 $Cart->addCartItem($item);
  276.                 $item->setCart($Cart);
  277.                 $Carts[$cartKey] = $Cart;
  278.             }
  279.         }
  280.         $this->estimateCarts = array_values($Carts);
  281.     }
  282.     /**
  283.      * カートに商品を追加します.
  284.      *
  285.      * @param $ProductClass ProductClass 商品規格
  286.      * @param $quantity int 数量
  287.      *
  288.      * @return bool 商品を追加できた場合はtrue
  289.      */
  290. //    public function addProduct($ProductClass, $quantity = 1)
  291. //    {
  292. //        if (!$ProductClass instanceof ProductClass) {
  293. //            $ProductClassId = $ProductClass;
  294. //            $ProductClass = $this->entityManager
  295. //                ->getRepository(ProductClass::class)
  296. //                ->find($ProductClassId);
  297. //            if (is_null($ProductClass)) {
  298. //                return false;
  299. //            }
  300. //        }
  301. //
  302. //        $ClassCategory1 = $ProductClass->getClassCategory1();
  303. //        if ($ClassCategory1 && !$ClassCategory1->isVisible()) {
  304. //            return false;
  305. //        }
  306. //        $ClassCategory2 = $ProductClass->getClassCategory2();
  307. //        if ($ClassCategory2 && !$ClassCategory2->isVisible()) {
  308. //            return false;
  309. //        }
  310. //
  311. //        $newItem = new CartItem();
  312. //        $newItem->setQuantity($quantity);
  313. //        $newItem->setPrice($ProductClass->getPrice02IncTax());
  314. //        $newItem->setProductClass($ProductClass);
  315. //
  316. //        $allCartItems = $this->mergeAllCartItems([$newItem]);
  317. //        $this->restoreCarts($allCartItems);
  318. //
  319. //        return true;
  320. //    }
  321.     public function removeProduct()
  322.     {
  323.         $allCartItems = $this->mergeAllCartItems();
  324.         $foundIndex = array_key_last($allCartItems);
  325.         array_splice($allCartItems, $foundIndex, 1);
  326.         $this->restoreCarts($allCartItems);
  327.         return true;
  328.     }
  329.     public function save($Customer = null)
  330.     {
  331.         if (null === $this->estimateCarts) {
  332.             $this->getCarts();
  333.         }
  334.         if (empty($this->estimateCarts)) {
  335.             return;
  336.         }
  337.         $cartKeys = [];
  338.         foreach ($this->estimateCarts as $Cart) {
  339.             if (is_null($Cart->getCustomer())) {
  340.                 if ($Customer) {
  341.                     $Cart->setCustomer($Customer);
  342.                 } else {
  343.                     $Cart->setCustomer($this->getUser());
  344.                 }
  345.             }
  346.             $this->entityManager->persist($Cart);
  347.             foreach ($Cart->getCartItems() as $item) {
  348.                 $this->entityManager->persist($item);
  349.             }
  350.             $this->entityManager->flush();
  351.             $cartKeys[] = $Cart->getCartKey();
  352.         }
  353.         $this->session->set('estimate_cart_keys', $cartKeys);
  354.         return;
  355.     }
  356.     /**
  357.      * @param  string $pre_estimate_id
  358.      *
  359.      * @return $this
  360.      */
  361.     public function setPreEstimateId($pre_estimate_id)
  362.     {
  363.         $this->getCart()->setPreEstimateId($pre_estimate_id);
  364.         return $this;
  365.     }
  366.     /**
  367.      * @return string|null
  368.      */
  369.     public function getPreEstimateId()
  370.     {
  371.         $Cart = $this->getCart();
  372.         if (!empty($Cart)) {
  373.             return $Cart->getPreEstimateId();
  374.         }
  375.         return null;
  376.     }
  377.     /**
  378.      * @return $this
  379.      */
  380.     public function clear()
  381.     {
  382.         $Carts = $this->getCarts();
  383.         if (!empty($Carts)) {
  384.             $removed = $this->getCart();
  385.             if ($removed && UnitOfWork::STATE_MANAGED === $this->entityManager->getUnitOfWork()->getEntityState($removed)) {
  386.                 $this->entityManager->remove($removed);
  387.                 $this->entityManager->flush();
  388.                 $cartKeys = [];
  389.                 foreach ($Carts as $key => $Cart) {
  390.                     // テーブルから削除されたカートを除外する
  391.                     if ($Cart == $removed) {
  392.                         unset($Carts[$key]);
  393.                     }
  394.                     $cartKeys[] = $Cart->getCartKey();
  395.                 }
  396.                 $this->session->set('estimate_cart_keys', $cartKeys);
  397.                 // 注文完了のカートキーをセッションから削除する
  398.                 $this->session->remove('estimate_cart_keys');
  399.                 $this->estimateCarts = $this->estimateCartRepository->findBy(['cart_key' => $cartKeys], ['id' => 'ASC']);
  400.             }
  401.         }
  402.         return $this;
  403.     }
  404.     /**
  405.      * @param CartItemComparator $cartItemComparator
  406.      */
  407. //    public function setCartItemComparator($cartItemComparator)
  408. //    {
  409. //        $this->cartItemComparator = $cartItemComparator;
  410. //    }
  411.     /**
  412.      * カートキーで指定したインデックスにあるカートを優先にする
  413.      *
  414.      * @param string $cartKey カートキー
  415.      */
  416.     public function setPrimary($cartKey)
  417.     {
  418.         $Carts = $this->getCarts();
  419.         $primary = $Carts[0];
  420.         $index = 0;
  421.         foreach ($Carts as $key => $Cart) {
  422.             if ($Cart->getCartKey() === $cartKey) {
  423.                 $index = $key;
  424.                 $primary = $Carts[$index];
  425.                 break;
  426.             }
  427.         }
  428.         $prev = $Carts[0];
  429.         array_splice($Carts, 0, 1, [$primary]);
  430.         array_splice($Carts, $index, 1, [$prev]);
  431.         $this->estimateCarts = $Carts;
  432.         $this->save();
  433.     }
  434.     protected function getUser()
  435.     {
  436.         if (null === $token = $this->tokenStorage->getToken()) {
  437.             return;
  438.         }
  439.         if (!is_object($user = $token->getUser())) {
  440.             // e.g. anonymous authentication
  441.             return;
  442.         }
  443.         return $user;
  444.     }
  445.     public function allocate(EstimateCartItem $Item)
  446.     {
  447.         $ProductClass = $Item->getProductClass();
  448.         if ($ProductClass && $ProductClass->getSaleType()) {
  449.             return (string) $ProductClass->getSaleType()->getId();
  450.         }
  451.         // @CHANGED カッティング基本加工料
  452. //        throw new \InvalidArgumentException('ProductClass/SaleType not found');
  453.     }
  454.     /**
  455.      * @param string $allocatedId
  456.      */
  457.     protected function createCartKey($allocatedId, Customer $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->estimateCartRepository->findOneBy(['cart_key' => $cartKey]);
  469.         } while ($Cart);
  470.         $this->session->set('cart_key_prefix', $random);
  471.         return $cartKey;
  472.     }
  473.     public function removeCartItem($CartItem)
  474.     {
  475.         $allCartItems = $this->mergeAllCartItems();
  476.         $foundIndex = -1;
  477.         foreach ($allCartItems as $index => $itemInCart) {
  478.             if ( $CartItem->getId() == $itemInCart->getId() ) {
  479.                 $foundIndex = $index;
  480.                 break;
  481.             }
  482.         }
  483.         if ( $foundIndex < 0 ) {
  484.             return;
  485.         }
  486.         array_splice($allCartItems, $foundIndex, 1);
  487.         $this->restoreCarts($allCartItems);
  488.     }
  489.     /**
  490.      * 既存の見積カート明細をその場で更新する(編集フォーム用).
  491.      * 明細 quantity は商品行数(1)固定。枚数は $materials 側に保持する.
  492.      */
  493.     public function updateCartItem(
  494.         EstimateCartItem $cartItem,
  495.         array $Options,
  496.         ?string $path,
  497.         ?array $materials,
  498.         $price,
  499.         ?string $originalFileName = null,
  500.         ?string $designImagePath = null
  501.     ): void {
  502.         $cartItem->setQuantity(1);
  503.         $cartItem->setPrice($price);
  504.         $cartItem->setOptions(json_encode($Options));
  505.         if ( !empty($materials) ) {
  506.             $cartItem->setMaterials(json_encode($materials));
  507.         }
  508.         if ( !empty($path) ) {
  509.             $cartItem->setSubmitFilePath($path);
  510.             if ( !empty($originalFileName) ) {
  511.                 $cartItem->setSubmitFileName($originalFileName);
  512.             }
  513.         }
  514.         if ( !empty($designImagePath) ) {
  515.             $cartItem->setDesignImagePath($designImagePath);
  516.         }
  517.     }
  518.     /**
  519.      * 商品をカートに追加
  520.      *
  521.      * @param $productClassId
  522.      * @param $Options
  523.      * @param $quantity
  524.      * @param $path
  525.      * @param $materials
  526.      * @param $price
  527.      * @param $original_file_name
  528.      * @return false|void
  529.      */
  530.     public function addProductOption($productClassId, $Options, $quantity = 1, $path = null, $materials = null, $price = 0, $original_file_name = null, $designImagePath = null)
  531.     {
  532.         $ProductClass = $this->productClassRepository->find($productClassId);
  533.         if(!$ProductClass) return false;
  534.         $EstimateItemType = $this->estimateItemTypeRepository->find(EstimateItemType::PRODUCT);
  535.         $newItem = new EstimateCartItem();
  536.         $newItem->setQuantity($quantity);
  537.         $newItem->setPrice($price);
  538.         $newItem->setProductClass($ProductClass);
  539.         $newItem->setOptions(json_encode($Options));
  540.         $newItem->setEstimateItemType($EstimateItemType);
  541.         if ( !empty($path) ) {
  542.             $newItem->setSubmitFilePath($path);
  543.             if ( !empty($original_file_name) ) {
  544.                 $newItem->setSubmitFileName($original_file_name);
  545.             }
  546.         }
  547.         if ( !empty($designImagePath) ) {
  548.             $newItem->setDesignImagePath($designImagePath);
  549.         }
  550.         if ( !empty($materials) ) {
  551.             $newItem->setMaterials(json_encode($materials));
  552.         }
  553. //        $allCartItems = [];
  554. //        foreach($this->getCarts() as $Cart){
  555. //            $CartItems = $Cart->getCartItems();
  556. //            $allCartItems = array_merge($allCartItems, $CartItems->toArray());
  557. //        }
  558. //
  559. //        $allCartItems[] = $newItem;
  560. //        $this->restoreCarts($allCartItems);
  561.         $allCartItems = $this->mergeAllCartItems([$newItem]);
  562.         $this->restoreCarts($allCartItems);
  563.     }
  564. }