src/Eccube/Service/PurchaseFlow/PurchaseFlow.php line 115

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\PurchaseFlow;
  13. use Doctrine\Common\Collections\ArrayCollection;
  14. use Eccube\Entity\ItemHolderInterface;
  15. use Eccube\Entity\ItemInterface;
  16. use Eccube\Entity\Order;
  17. use Eccube\Entity\OrderItem;
  18. class PurchaseFlow
  19. {
  20.     /**
  21.      * @var string
  22.      */
  23.     protected $flowType;
  24.     /**
  25.      * @var ArrayCollection|ItemPreprocessor[]
  26.      */
  27.     protected $itemPreprocessors;
  28.     /**
  29.      * @var ArrayCollection|ItemHolderPreprocessor[]
  30.      */
  31.     protected $itemHolderPreprocessors;
  32.     /**
  33.      * @var ArrayCollection|ItemValidator[]
  34.      */
  35.     protected $itemValidators;
  36.     /**
  37.      * @var ArrayCollection|ItemHolderValidator[]
  38.      */
  39.     protected $itemHolderValidators;
  40.     /**
  41.      * @var ArrayCollection|ItemHolderPostValidator[]
  42.      */
  43.     protected $itemHolderPostValidators;
  44.     /**
  45.      * @var ArrayCollection|DiscountProcessor[]
  46.      */
  47.     protected $discountProcessors;
  48.     /**
  49.      * @var ArrayCollection|PurchaseProcessor[]
  50.      */
  51.     protected $purchaseProcessors;
  52.     public function __construct()
  53.     {
  54.         $this->purchaseProcessors = new ArrayCollection();
  55.         $this->itemValidators = new ArrayCollection();
  56.         $this->itemHolderValidators = new ArrayCollection();
  57.         $this->itemPreprocessors = new ArrayCollection();
  58.         $this->itemHolderPreprocessors = new ArrayCollection();
  59.         $this->itemHolderPostValidators = new ArrayCollection();
  60.         $this->discountProcessors = new ArrayCollection();
  61.     }
  62.     public function setFlowType($flowType)
  63.     {
  64.         $this->flowType $flowType;
  65.     }
  66.     public function setPurchaseProcessors(ArrayCollection $processors)
  67.     {
  68.         $this->purchaseProcessors $processors;
  69.     }
  70.     public function setItemValidators(ArrayCollection $itemValidators)
  71.     {
  72.         $this->itemValidators $itemValidators;
  73.     }
  74.     public function setItemHolderValidators(ArrayCollection $itemHolderValidators)
  75.     {
  76.         $this->itemHolderValidators $itemHolderValidators;
  77.     }
  78.     public function setItemPreprocessors(ArrayCollection $itemPreprocessors)
  79.     {
  80.         $this->itemPreprocessors $itemPreprocessors;
  81.     }
  82.     public function setItemHolderPreprocessors(ArrayCollection $itemHolderPreprocessors)
  83.     {
  84.         $this->itemHolderPreprocessors $itemHolderPreprocessors;
  85.     }
  86.     public function setItemHolderPostValidators(ArrayCollection $itemHolderPostValidators)
  87.     {
  88.         $this->itemHolderPostValidators $itemHolderPostValidators;
  89.     }
  90.     public function setDiscountProcessors(ArrayCollection $discountProcessors)
  91.     {
  92.         $this->discountProcessors $discountProcessors;
  93.     }
  94.     public function validate(ItemHolderInterface $itemHolderPurchaseContext $context)
  95.     {
  96.         $context->setFlowType($this->flowType);
  97.         $this->calculateAll($itemHolder);
  98.         $flowResult = new PurchaseFlowResult($itemHolder);
  99.         foreach ($itemHolder->getItems() as $item) {
  100.             foreach ($this->itemValidators as $itemValidator) {
  101.                 $result $itemValidator->execute($item$context);
  102.                 $flowResult->addProcessResult($result);
  103.             }
  104.         }
  105.         $this->calculateAll($itemHolder);
  106.         foreach ($this->itemHolderValidators as $itemHolderValidator) {
  107.             $result $itemHolderValidator->execute($itemHolder$context);
  108.             $flowResult->addProcessResult($result);
  109.         }
  110.         $this->calculateAll($itemHolder);
  111.         foreach ($itemHolder->getItems() as $item) {
  112.             foreach ($this->itemPreprocessors as $itemPreprocessor) {
  113.                 $itemPreprocessor->process($item$context);
  114.             }
  115.         }
  116.         $this->calculateAll($itemHolder);
  117.         foreach ($this->itemHolderPreprocessors as $holderPreprocessor) {
  118.             $result $holderPreprocessor->process($itemHolder$context);
  119.             if ($result) {
  120.                 $flowResult->addProcessResult($result);
  121.             }
  122.             $this->calculateAll($itemHolder);
  123.         }
  124.         foreach ($this->discountProcessors as $discountProcessor) {
  125.             $discountProcessor->removeDiscountItem($itemHolder$context);
  126.         }
  127.         $this->calculateAll($itemHolder);
  128.         foreach ($this->discountProcessors as $discountProcessor) {
  129.             $result $discountProcessor->addDiscountItem($itemHolder$context);
  130.             if ($result) {
  131.                 $flowResult->addProcessResult($result);
  132.             }
  133.             $this->calculateAll($itemHolder);
  134.         }
  135.         foreach ($this->itemHolderPostValidators as $itemHolderPostValidator) {
  136.             $result $itemHolderPostValidator->execute($itemHolder$context);
  137.             $flowResult->addProcessResult($result);
  138.             $this->calculateAll($itemHolder);
  139.         }
  140.         return $flowResult;
  141.     }
  142.     /**
  143.      * 購入フロー仮確定処理.
  144.      *
  145.      * @param ItemHolderInterface $target
  146.      * @param PurchaseContext $context
  147.      *
  148.      * @throws PurchaseException
  149.      */
  150.     public function prepare(ItemHolderInterface $targetPurchaseContext $context)
  151.     {
  152.         $context->setFlowType($this->flowType);
  153.         foreach ($this->purchaseProcessors as $processor) {
  154.             $processor->prepare($target$context);
  155.         }
  156.     }
  157.     /**
  158.      * 購入フロー確定処理.
  159.      *
  160.      * @param ItemHolderInterface $target
  161.      * @param PurchaseContext $context
  162.      *
  163.      * @throws PurchaseException
  164.      */
  165.     public function commit(ItemHolderInterface $targetPurchaseContext $context)
  166.     {
  167.         $context->setFlowType($this->flowType);
  168.         foreach ($this->purchaseProcessors as $processor) {
  169.             $processor->commit($target$context);
  170.         }
  171.     }
  172.     /**
  173.      * 購入フロー仮確定取り消し処理.
  174.      *
  175.      * @param ItemHolderInterface $target
  176.      * @param PurchaseContext $context
  177.      */
  178.     public function rollback(ItemHolderInterface $targetPurchaseContext $context)
  179.     {
  180.         $context->setFlowType($this->flowType);
  181.         foreach ($this->purchaseProcessors as $processor) {
  182.             $processor->rollback($target$context);
  183.         }
  184.     }
  185.     public function addPurchaseProcessor(PurchaseProcessor $processor)
  186.     {
  187.         $this->purchaseProcessors[] = $processor;
  188.     }
  189.     public function addItemHolderPreprocessor(ItemHolderPreprocessor $holderPreprocessor)
  190.     {
  191.         $this->itemHolderPreprocessors[] = $holderPreprocessor;
  192.     }
  193.     public function addItemPreprocessor(ItemPreprocessor $itemPreprocessor)
  194.     {
  195.         $this->itemPreprocessors[] = $itemPreprocessor;
  196.     }
  197.     public function addItemValidator(ItemValidator $itemValidator)
  198.     {
  199.         $this->itemValidators[] = $itemValidator;
  200.     }
  201.     public function addItemHolderValidator(ItemHolderValidator $itemHolderValidator)
  202.     {
  203.         $this->itemHolderValidators[] = $itemHolderValidator;
  204.     }
  205.     public function addItemHolderPostValidator(ItemHolderPostValidator $itemHolderValidator)
  206.     {
  207.         $this->itemHolderPostValidators[] = $itemHolderValidator;
  208.     }
  209.     public function addDiscountProcessor(DiscountProcessor $discountProcessor)
  210.     {
  211.         $this->discountProcessors[] = $discountProcessor;
  212.     }
  213.     /**
  214.      * @param ItemHolderInterface $itemHolder
  215.      */
  216.     protected function calculateTotal(ItemHolderInterface $itemHolder)
  217.     {
  218.         $total array_reduce($itemHolder->getItems()->toArray(), function ($sumItemInterface $item) {
  219.             $sum += $item->getPriceIncTax() * $item->getQuantity();
  220.             return $sum;
  221.         }, 0);
  222.         $itemHolder->setTotal($total);
  223.         // TODO
  224.         if ($itemHolder instanceof Order) {
  225.             // Order には PaymentTotal もセットする
  226.             $itemHolder->setPaymentTotal($total);
  227.         }
  228.     }
  229.     protected function calculateSubTotal(ItemHolderInterface $itemHolder)
  230.     {
  231.         $total $itemHolder->getItems()
  232.             ->getProductClasses()
  233.             ->reduce(function ($sumItemInterface $item) {
  234.                 $sum += $item->getPriceIncTax() * $item->getQuantity();
  235.                 return $sum;
  236.             }, 0);
  237.         // TODO
  238.         if ($itemHolder instanceof Order) {
  239.             // Order の場合は SubTotal をセットする
  240.             $itemHolder->setSubTotal($total);
  241.         }
  242.     }
  243.     /**
  244.      * @param ItemHolderInterface $itemHolder
  245.      */
  246.     protected function calculateDeliveryFeeTotal(ItemHolderInterface $itemHolder)
  247.     {
  248.         $total $itemHolder->getItems()
  249.             ->getDeliveryFees()
  250.             ->reduce(function ($sumItemInterface $item) {
  251.                 $sum += $item->getPriceIncTax() * $item->getQuantity();
  252.                 return $sum;
  253.             }, 0);
  254.         $itemHolder->setDeliveryFeeTotal($total);
  255.     }
  256.     /**
  257.      * @param ItemHolderInterface $itemHolder
  258.      */
  259.     protected function calculateDiscount(ItemHolderInterface $itemHolder)
  260.     {
  261.         $total $itemHolder->getItems()
  262.             ->getDiscounts()
  263.             ->reduce(function ($sumItemInterface $item) {
  264.                 $sum += $item->getPriceIncTax() * $item->getQuantity();
  265.                 return $sum;
  266.             }, 0);
  267.         // TODO 後方互換のため discount には正の整数を代入する
  268.         $itemHolder->setDiscount($total * -1);
  269.     }
  270.     /**
  271.      * @param ItemHolderInterface $itemHolder
  272.      */
  273.     protected function calculateCharge(ItemHolderInterface $itemHolder)
  274.     {
  275.         $total $itemHolder->getItems()
  276.             ->getCharges()
  277.             ->reduce(function ($sumItemInterface $item) {
  278.                 $sum += $item->getPriceIncTax() * $item->getQuantity();
  279.                 return $sum;
  280.             }, 0);
  281.         $itemHolder->setCharge($total);
  282.     }
  283.     /**
  284.      * @param ItemHolderInterface $itemHolder
  285.      */
  286.     protected function calculateTax(ItemHolderInterface $itemHolder)
  287.     {
  288.         $total $itemHolder->getItems()
  289.             ->reduce(function ($sumItemInterface $item) {
  290.                 if ($item instanceof OrderItem) {
  291.                     $sum += $item->getTax() * $item->getQuantity();
  292.                 } else {
  293.                     $sum += ($item->getPriceIncTax() - $item->getPrice()) * $item->getQuantity();
  294.                 }
  295.                 return $sum;
  296.             }, 0);
  297.         $itemHolder->setTax($total);
  298.     }
  299.     /**
  300.      * @param ItemHolderInterface $itemHolder
  301.      */
  302.     protected function calculateAll(ItemHolderInterface $itemHolder)
  303.     {
  304.         $this->calculateDeliveryFeeTotal($itemHolder);
  305.         $this->calculateCharge($itemHolder);
  306.         $this->calculateDiscount($itemHolder);
  307.         $this->calculateSubTotal($itemHolder); // Order の場合のみ
  308.         $this->calculateTax($itemHolder);
  309.         $this->calculateTotal($itemHolder);
  310.     }
  311.     /**
  312.      * PurchaseFlow をツリー表示します.
  313.      *
  314.      * @return string
  315.      */
  316.     public function dump()
  317.     {
  318.         $callback = function ($processor) {
  319.             return get_class($processor);
  320.         };
  321.         $flows = [
  322.             => $this->flowType.' flow',
  323.             'ItemValidator' => $this->itemValidators->map($callback)->toArray(),
  324.             'ItemHolderValidator' => $this->itemHolderValidators->map($callback)->toArray(),
  325.             'ItemPreprocessor' => $this->itemPreprocessors->map($callback)->toArray(),
  326.             'ItemHolderPreprocessor' => $this->itemHolderPreprocessors->map($callback)->toArray(),
  327.             'DiscountProcessor' => $this->discountProcessors->map($callback)->toArray(),
  328.             'ItemHolderPostValidator' => $this->itemHolderPostValidators->map($callback)->toArray(),
  329.         ];
  330.         $tree = new \RecursiveTreeIterator(new \RecursiveArrayIterator($flows));
  331.         $tree->setPrefixPart(\RecursiveTreeIterator::PREFIX_RIGHT' ');
  332.         $tree->setPrefixPart(\RecursiveTreeIterator::PREFIX_MID_LAST' ');
  333.         $tree->setPrefixPart(\RecursiveTreeIterator::PREFIX_MID_HAS_NEXT'│');
  334.         $tree->setPrefixPart(\RecursiveTreeIterator::PREFIX_END_HAS_NEXT'├');
  335.         $tree->setPrefixPart(\RecursiveTreeIterator::PREFIX_END_LAST'└');
  336.         $out '';
  337.         foreach ($tree as $key => $value) {
  338.             if (is_numeric($key)) {
  339.                 $out .= $value.PHP_EOL;
  340.             } else {
  341.                 $out .= $key.PHP_EOL;
  342.             }
  343.         }
  344.         return $out;
  345.     }
  346.     /**
  347.      * @return string
  348.      */
  349.     public function __toString()
  350.     {
  351.         return $this->dump();
  352.     }
  353. }