Failed Conditions
Pull Request — 4.0 (#4276)
by Kiyotaka
05:16
created

OrderHelper::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 27

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 12
dl 0
loc 27
ccs 13
cts 13
cp 1
crap 1
rs 9.488
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
/*
4
 * This file is part of EC-CUBE
5
 *
6
 * Copyright(c) EC-CUBE CO.,LTD. All Rights Reserved.
7
 *
8
 * http://www.ec-cube.co.jp/
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Eccube\Service;
15
16
use Doctrine\Common\Collections\ArrayCollection;
17
use Doctrine\Common\Collections\Collection;
18
use Doctrine\ORM\EntityManagerInterface;
19
use Eccube\Entity\Cart;
20
use Eccube\Entity\CartItem;
21
use Eccube\Entity\Customer;
22
use Eccube\Entity\Master\DeviceType;
23
use Eccube\Entity\Master\OrderItemType;
24
use Eccube\Entity\Master\OrderStatus;
25
use Eccube\Entity\Order;
26
use Eccube\Entity\OrderItem;
27
use Eccube\Entity\Shipping;
28
use Eccube\Entity\TaxRule;
29
use Eccube\EventListener\SecurityListener;
30
use Eccube\Repository\DeliveryRepository;
31
use Eccube\Repository\Master\DeviceTypeRepository;
32
use Eccube\Repository\Master\OrderItemTypeRepository;
33
use Eccube\Repository\Master\OrderStatusRepository;
34
use Eccube\Repository\Master\PrefRepository;
35
use Eccube\Repository\OrderRepository;
36
use Eccube\Repository\PaymentRepository;
37
use Eccube\Repository\TaxRuleRepository;
38
use Eccube\Util\StringUtil;
39
use SunCat\MobileDetectBundle\DeviceDetector\MobileDetector;
40
use Symfony\Bundle\FrameworkBundle\Controller\ControllerTrait;
41
use Symfony\Component\DependencyInjection\ContainerInterface;
42
use Symfony\Component\HttpFoundation\Session\SessionInterface;
43
44
class OrderHelper
45
{
46
    // FIXME 必要なメソッドのみ移植する
47
    use ControllerTrait;
48
49
    /**
50
     * @var ContainerInterface
51
     */
52
    protected $container;
53
54
    /**
55
     * @var string 非会員情報を保持するセッションのキー
56
     */
57
    const SESSION_NON_MEMBER = 'eccube.front.shopping.nonmember';
58
59
    /**
60
     * @var string 非会員の住所情報を保持するセッションのキー
61
     */
62
    const SESSION_NON_MEMBER_ADDRESSES = 'eccube.front.shopping.nonmember.customeraddress';
63
64
    /**
65
     * @var string 受注IDを保持するセッションのキー
66
     */
67
    const SESSION_ORDER_ID = 'eccube.front.shopping.order.id';
68
69
    /**
70
     * @var string カートが分割されているかどうかのフラグ. 購入フローからのログイン時にカートが分割された場合にtrueがセットされる.
71
     *
72
     * @see SecurityListener
73
     */
74
    const SESSION_CART_DIVIDE_FLAG = 'eccube.front.cart.divide';
75
76
    /**
77
     * @var SessionInterface
78
     */
79
    protected $session;
80
81
    /**
82
     * @var PrefRepository
83
     */
84
    protected $prefRepository;
85
86
    /**
87
     * @var OrderRepository
88
     */
89
    protected $orderRepository;
90
91
    /**
92
     * @var OrderItemTypeRepository
93
     */
94
    protected $orderItemTypeRepository;
95
96
    /**
97
     * @var OrderStatusRepository
98
     */
99
    protected $orderStatusRepository;
100
101
    /**
102
     * @var DeliveryRepository
103
     */
104
    protected $deliveryRepository;
105
106
    /**
107
     * @var PaymentRepository
108
     */
109
    protected $paymentRepository;
110
111
    /**
112
     * @var DeviceTypeRepository
113
     */
114
    protected $deviceTypeRepository;
115 175
116
    /**
117
     * @var EntityManagerInterface
118
     */
119
    protected $entityManager;
120
121
    /**
122
     * @var MobileDetector
123
     */
124
    protected $mobileDetector;
125
126
    /**
127
     * @var TaxRuleRepository
128 175
     */
129 175
    protected $taxRuleRepository;
130 175
131 175
    public function __construct(
132 175
        ContainerInterface $container,
133 175
        EntityManagerInterface $entityManager,
134 175
        OrderRepository $orderRepository,
135 175
        OrderItemTypeRepository $orderItemTypeRepository,
136 175
        OrderStatusRepository $orderStatusRepository,
137 175
        DeliveryRepository $deliveryRepository,
138 175
        PaymentRepository $paymentRepository,
139
        DeviceTypeRepository $deviceTypeRepository,
140
        PrefRepository $prefRepository,
141
        TaxRuleRepository $taxRuleRepository,
142
        MobileDetector $mobileDetector,
143
        SessionInterface $session
144
    ) {
145
        $this->container = $container;
146
        $this->orderRepository = $orderRepository;
147
        $this->orderStatusRepository = $orderStatusRepository;
148
        $this->orderItemTypeRepository = $orderItemTypeRepository;
149 51
        $this->deliveryRepository = $deliveryRepository;
150
        $this->paymentRepository = $paymentRepository;
151 51
        $this->deviceTypeRepository = $deviceTypeRepository;
152 51
        $this->entityManager = $entityManager;
153
        $this->prefRepository = $prefRepository;
154 51
        $this->taxRuleRepository = $taxRuleRepository;
155
        $this->mobileDetector = $mobileDetector;
156 51
        $this->session = $session;
157
    }
158
159
    /**
160 51
     * 購入処理中の受注を生成する.
161
     *
162 51
     * @param Customer $Customer
163 51
     * @param $CartItems
164
     *
165
     * @return Order
166 51
     */
167 51
    public function createPurchaseProcessingOrder(Cart $Cart, Customer $Customer)
168
    {
169 51
        /** @var OrderStatus $OrderStatus */
170 51
        $OrderStatus = $this->orderStatusRepository->find(OrderStatus::PROCESSING);
171
        $Order = new Order($OrderStatus);
172 51
173 51
        $preOrderId = $this->createPreOrderId();
174
        $Order->setPreOrderId($preOrderId);
175 51
176 51
        // 顧客情報の設定
177 51
        $this->setCustomer($Order, $Customer);
178 51
179 51
        /** @var DeviceType $DeviceType */
180 51
        $DeviceType = $this->deviceTypeRepository->find($this->mobileDetector->isMobile() ? DeviceType::DEVICE_TYPE_MB : DeviceType::DEVICE_TYPE_PC);
181 51
        $Order->setDeviceType($DeviceType);
182
183
        // 明細情報の設定
184 51
        $OrderItems = $this->createOrderItemsFromCartItems($Cart->getCartItems());
185
        $OrderItemsGroupBySaleType = array_reduce($OrderItems, function ($result, $item) {
186 51
            /* @var OrderItem $item */
187
            $saleTypeId = $item->getProductClass()->getSaleType()->getId();
188
            $result[$saleTypeId][] = $item;
189 51
190
            return $result;
191
        }, []);
192
193
        foreach ($OrderItemsGroupBySaleType as $OrderItems) {
194
            $Shipping = $this->createShippingFromCustomer($Customer);
195
            $Shipping->setOrder($Order);
196
            $this->addOrderItems($Order, $Shipping, $OrderItems);
197
            $this->setDefaultDelivery($Shipping);
198
            $this->entityManager->persist($Shipping);
199 2
            $Order->addShipping($Shipping);
200
        }
201 2
202 2
        $this->setDefaultPayment($Order);
203
204 2
        $this->entityManager->persist($Order);
205 1
206 1
        return $Order;
207 1
    }
208 1
209 1
    /**
210 1
     * @param Cart $Cart
211 1
     *
212
     * @return bool
213
     */
214 2
    public function verifyCart(Cart $Cart)
215
    {
216
        if (count($Cart->getCartItems()) > 0) {
217 51
            $divide = $this->session->get(self::SESSION_CART_DIVIDE_FLAG);
218
            if ($divide) {
219
                log_info('ログイン時に販売種別が異なる商品がカートと結合されました。');
220
221 51
                return false;
222
            }
223 51
224
            return true;
225 51
        }
226
227
        log_info('カートに商品が入っていません。');
228
229 51
        return false;
230
    }
231 51
232
    /**
233
     * 注文手続き画面でログインが必要かどうかの判定
234 51
     *
235
     * @return bool
236 51
     */
237 34
    public function isLoginRequired()
238
    {
239
        // フォームログイン済はログイン不要
240 51
        if ($this->isGranted('IS_AUTHENTICATED_FULLY')) {
241 51
            return false;
242
        }
243 51
244
        // Remember Meログイン済の場合はフォームからのログインが必要
245
        if ($this->isGranted('IS_AUTHENTICATED_REMEMBERED')) {
246
            return true;
247
        }
248
249
        // 未ログインだがお客様情報を入力している場合はログイン不要
250
        if (!$this->getUser() && $this->getNonMember()) {
251
            return false;
252
        }
253
254
        return true;
255
    }
256 51
257
    /**
258 51
     * 購入処理中の受注を取得する.
259
     *
260 51
     * @param null|string $preOrderId
261
     *
262
     * @return null|Order
263 51
     */
264
    public function getPurchaseProcessingOrder($preOrderId = null)
265 51
    {
266
        if (null === $preOrderId) {
267 51
            return null;
268
        }
269 51
270 51
        return $this->orderRepository->findOneBy([
271 51
            'pre_order_id' => $preOrderId,
272 51
            'OrderStatus' => OrderStatus::PROCESSING,
273 51
        ]);
274 51
    }
275 51
276
    /**
277 51
     * セッションに保持されている非会員情報を取得する.
278 51
     * 非会員購入時に入力されたお客様情報を返す.
279 51
     *
280 51
     * @return Customer
281
     */
282 51
    public function getNonMember()
283 51
    {
284 42
        $NonMember = $this->session->get(self::SESSION_NON_MEMBER);
285 42
        if ($NonMember && $NonMember->getPref()) {
286
            $Pref = $this->prefRepository->find($NonMember->getPref()->getId());
287
            $NonMember->setPref($Pref);
288 51
        }
289 51
290
        return $NonMember;
291
    }
292 51
293
    /**
294 51
     * @param Cart $Cart
295
     * @param Customer $Customer
296 51
     *
297 51
     * @return Order|null
298 51
     */
299 51
    public function initializeOrder(Cart $Cart, Customer $Customer)
300 51
    {
301 51
        // 購入処理中の受注情報を取得
302 51
        if ($Order = $this->getPurchaseProcessingOrder($Cart->getPreOrderId())) {
303 51
            return $Order;
304 51
        }
305 51
306
        // 受注情報を作成
307 51
        $Order = $this->createPurchaseProcessingOrder($Cart, $Customer);
308
        $Cart->setPreOrderId($Order->getPreOrderId());
309
310 51
        return $Order;
311
    }
312
313 51
    public function removeSession()
314 51
    {
315
        $this->session->remove(self::SESSION_ORDER_ID);
316 51
        $this->session->remove(self::SESSION_ORDER_ID);
317 51
        $this->session->remove(self::SESSION_NON_MEMBER);
318 51
        $this->session->remove(self::SESSION_NON_MEMBER_ADDRESSES);
319 51
    }
320
321
    /**
322
     * 会員情報の更新日時が受注の作成日時よりも新しければ, 受注の注文者情報を更新する.
323 51
     *
324
     * @param Order $Order
325
     * @param Customer $Customer
326 51
     */
327 51
    public function updateCustomerInfo(Order $Order, Customer $Customer)
328 51
    {
329
        if ($Order->getCreateDate() < $Customer->getUpdateDate()) {
330
            $this->setCustomer($Order, $Customer);
331 51
        }
332
    }
333 51
334
    public function createPreOrderId()
335
    {
336 51
        // ランダムなpre_order_idを作成
337
        do {
338 51
            $preOrderId = sha1(StringUtil::random(32));
339 51
340 51
            $Order = $this->orderRepository->findOneBy(
341
                [
342
                    'pre_order_id' => $preOrderId,
343
                ]
344 51
            );
345 51
        } while ($Order);
346
347
        return $preOrderId;
348
    }
349 51
350
    protected function setCustomer(Order $Order, Customer $Customer)
351
    {
352 51
        if ($Customer->getId()) {
353
            $Order->setCustomer($Customer);
354
        }
355 51
356 51
        $Order->copyProperties(
357 51
            $Customer,
358 51
            [
359
                'id',
360
                'create_date',
361
                'update_date',
362 51
                'del_flg',
363
            ]
364 51
        );
365 51
    }
366 51
367 51
    /**
368 51
     * @param Collection|ArrayCollection|CartItem[] $CartItems
369
     *
370
     * @return OrderItem[]
371
     */
372
    protected function createOrderItemsFromCartItems($CartItems)
373
    {
374
        /** @var OrderItemType $ProductItemType */
375
        $ProductItemType = $this->orderItemTypeRepository->find(OrderItemType::PRODUCT);
376
377
        return array_map(function ($item) use ($ProductItemType) {
378
            /* @var $item CartItem */
379
            /* @var $ProductClass \Eccube\Entity\ProductClass */
380
            $ProductClass = $item->getProductClass();
381
            /* @var $Product \Eccube\Entity\Product */
382
            $Product = $ProductClass->getProduct();
383
            /** @var TaxRule $TaxRule */
384
            $TaxRule = $this->taxRuleRepository->getByRule($Product, $ProductClass)
385
                ?: $this->taxRuleRepository->getByRule();
386
387
            $OrderItem = new OrderItem();
388
            $OrderItem
389
                ->setProduct($Product)
390
                ->setProductClass($ProductClass)
391
                ->setProductName($Product->getName())
392
                ->setProductCode($ProductClass->getCode())
393
                ->setPrice($ProductClass->getPrice02())
394
                ->setQuantity($item->getQuantity())
395
                ->setOrderItemType($ProductItemType)
396
                ->setTaxRate($TaxRule->getTaxRate())
397
                ->setTaxAdjust($TaxRule->getTaxAdjust())
398
                ->setRoundingType($TaxRule->getRoundingType());
399
400
            $ClassCategory1 = $ProductClass->getClassCategory1();
401
            if (!is_null($ClassCategory1)) {
402
                $OrderItem->setClasscategoryName1($ClassCategory1->getName());
403
                $OrderItem->setClassName1($ClassCategory1->getClassName()->getName());
404
            }
405
            $ClassCategory2 = $ProductClass->getClassCategory2();
406
            if (!is_null($ClassCategory2)) {
407
                $OrderItem->setClasscategoryName2($ClassCategory2->getName());
408
                $OrderItem->setClassName2($ClassCategory2->getClassName()->getName());
409
            }
410
411
            return $OrderItem;
412
        }, $CartItems instanceof Collection ? $CartItems->toArray() : $CartItems);
413
    }
414
415
    /**
416
     * @param Customer $Customer
417
     *
418
     * @return Shipping
419
     */
420
    protected function createShippingFromCustomer(Customer $Customer)
421
    {
422
        $Shipping = new Shipping();
423
        $Shipping
424
            ->setName01($Customer->getName01())
425
            ->setName02($Customer->getName02())
426
            ->setKana01($Customer->getKana01())
427
            ->setKana02($Customer->getKana02())
428
            ->setCompanyName($Customer->getCompanyName())
429
            ->setPhoneNumber($Customer->getPhoneNumber())
430
            ->setPostalCode($Customer->getPostalCode())
431
            ->setPref($Customer->getPref())
432
            ->setAddr01($Customer->getAddr01())
433
            ->setAddr02($Customer->getAddr02());
434
435
        return $Shipping;
436
    }
437
438
    /**
439
     * @param Shipping $Shipping
440
     */
441
    protected function setDefaultDelivery(Shipping $Shipping)
442
    {
443
        // 配送商品に含まれる販売種別を抽出.
444
        $OrderItems = $Shipping->getOrderItems();
445
        $SaleTypes = [];
446
        /** @var OrderItem $OrderItem */
447 View Code Duplication
        foreach ($OrderItems as $OrderItem) {
448
            $ProductClass = $OrderItem->getProductClass();
449
            $SaleType = $ProductClass->getSaleType();
450
            $SaleTypes[$SaleType->getId()] = $SaleType;
451
        }
452
453
        // 販売種別に紐づく配送業者を取得.
454
        $Deliveries = $this->deliveryRepository->getDeliveries($SaleTypes);
455
456
        // 初期の配送業者を設定
457
        $Delivery = current($Deliveries);
458
        $Shipping->setDelivery($Delivery);
459
        $Shipping->setShippingDeliveryName($Delivery->getName());
460
    }
461
462
    /**
463
     * @param Order $Order
464
     */
465
    protected function setDefaultPayment(Order $Order)
466
    {
467
        $OrderItems = $Order->getOrderItems();
468
469
        // 受注明細に含まれる販売種別を抽出.
470
        $SaleTypes = [];
471
        /** @var OrderItem $OrderItem */
472 View Code Duplication
        foreach ($OrderItems as $OrderItem) {
473
            $ProductClass = $OrderItem->getProductClass();
474
            if (is_null($ProductClass)) {
475
                // 商品明細のみ対象とする. 送料明細等はスキップする.
476
                continue;
477
            }
478
            $SaleType = $ProductClass->getSaleType();
479
            $SaleTypes[$SaleType->getId()] = $SaleType;
480
        }
481
482
        // 販売種別に紐づく配送業者を抽出
483
        $Deliveries = $this->deliveryRepository->getDeliveries($SaleTypes);
484
485
        // 利用可能な支払い方法を抽出.
486
        $Payments = $this->paymentRepository->findAllowedPayments($Deliveries, true);
487
488
        // 初期の支払い方法を設定.
489
        $Payment = current($Payments);
490
        if ($Payment) {
491
            $Order->setPayment($Payment);
492
            $Order->setPaymentMethod($Payment->getMethod());
493
        }
494
    }
495
496
    /**
497
     * @param Order $Order
498
     * @param Shipping $Shipping
499
     * @param array $OrderItems
500
     */
501
    protected function addOrderItems(Order $Order, Shipping $Shipping, array $OrderItems)
502
    {
503
        foreach ($OrderItems as $OrderItem) {
504
            $Shipping->addOrderItem($OrderItem);
505
            $Order->addOrderItem($OrderItem);
506
            $OrderItem->setOrder($Order);
507
            $OrderItem->setShipping($Shipping);
508
        }
509
    }
510
}
511