Failed Conditions
Pull Request — 4.0 (#4276)
by Kiyotaka
04:32
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
        $OrderStatus = $this->orderStatusRepository->find(OrderStatus::PROCESSING);
170 51
        $Order = new Order($OrderStatus);
0 ignored issues
show
Bug introduced by
It seems like $OrderStatus defined by $this->orderStatusReposi...rderStatus::PROCESSING) on line 169 can also be of type object; however, Eccube\Entity\Order::__construct() does only seem to accept null|object<Eccube\Entity\Master\OrderStatus>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
171
172 51
        $preOrderId = $this->createPreOrderId();
173 51
        $Order->setPreOrderId($preOrderId);
174
175 51
        // 顧客情報の設定
176 51
        $this->setCustomer($Order, $Customer);
177 51
178 51
        $DeviceType = $this->deviceTypeRepository->find($this->mobileDetector->isMobile() ? DeviceType::DEVICE_TYPE_MB : DeviceType::DEVICE_TYPE_PC);
179 51
        $Order->setDeviceType($DeviceType);
0 ignored issues
show
Bug introduced by
It seems like $DeviceType defined by $this->deviceTypeReposit...ceType::DEVICE_TYPE_PC) on line 178 can also be of type object; however, Eccube\Entity\Order::setDeviceType() does only seem to accept null|object<Eccube\Entity\Master\DeviceType>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
180 51
181 51
        // 明細情報の設定
182
        $OrderItems = $this->createOrderItemsFromCartItems($Cart->getCartItems());
183
        $OrderItemsGroupBySaleType = array_reduce($OrderItems, function ($result, $item) {
184 51
            /* @var OrderItem $item */
185
            $saleTypeId = $item->getProductClass()->getSaleType()->getId();
186 51
            $result[$saleTypeId][] = $item;
187
188
            return $result;
189 51
        }, []);
190
191
        foreach ($OrderItemsGroupBySaleType as $OrderItems) {
192
            $Shipping = $this->createShippingFromCustomer($Customer);
193
            $Shipping->setOrder($Order);
194
            $this->addOrderItems($Order, $Shipping, $OrderItems);
195
            $this->setDefaultDelivery($Shipping);
196
            $this->entityManager->persist($Shipping);
197
            $Order->addShipping($Shipping);
198
        }
199 2
200
        $this->setDefaultPayment($Order);
201 2
202 2
        $this->entityManager->persist($Order);
203
204 2
        return $Order;
205 1
    }
206 1
207 1
    /**
208 1
     * @param Cart $Cart
209 1
     *
210 1
     * @return bool
211 1
     */
212
    public function verifyCart(Cart $Cart)
213
    {
214 2
        if (count($Cart->getCartItems()) > 0) {
215
            $divide = $this->session->get(self::SESSION_CART_DIVIDE_FLAG);
216
            if ($divide) {
217 51
                log_info('ログイン時に販売種別が異なる商品がカートと結合されました。');
218
219
                return false;
220
            }
221 51
222
            return true;
223 51
        }
224
225 51
        log_info('カートに商品が入っていません。');
226
227
        return false;
228
    }
229 51
230
    /**
231 51
     * 注文手続き画面でログインが必要かどうかの判定
232
     *
233
     * @return bool
234 51
     */
235
    public function isLoginRequired()
236 51
    {
237 34
        // フォームログイン済はログイン不要
238
        if ($this->isGranted('IS_AUTHENTICATED_FULLY')) {
239
            return false;
240 51
        }
241 51
242
        // Remember Meログイン済の場合はフォームからのログインが必要
243 51
        if ($this->isGranted('IS_AUTHENTICATED_REMEMBERED')) {
244
            return true;
245
        }
246
247
        // 未ログインだがお客様情報を入力している場合はログイン不要
248
        if (!$this->getUser() && $this->getNonMember()) {
249
            return false;
250
        }
251
252
        return true;
253
    }
254
255
    /**
256 51
     * 購入処理中の受注を取得する.
257
     *
258 51
     * @param null|string $preOrderId
259
     *
260 51
     * @return null|Order
261
     */
262
    public function getPurchaseProcessingOrder($preOrderId = null)
263 51
    {
264
        if (null === $preOrderId) {
265 51
            return null;
266
        }
267 51
268
        return $this->orderRepository->findOneBy([
269 51
            'pre_order_id' => $preOrderId,
270 51
            'OrderStatus' => OrderStatus::PROCESSING,
271 51
        ]);
272 51
    }
273 51
274 51
    /**
275 51
     * セッションに保持されている非会員情報を取得する.
276
     * 非会員購入時に入力されたお客様情報を返す.
277 51
     *
278 51
     * @return Customer
279 51
     */
280 51
    public function getNonMember()
281
    {
282 51
        $NonMember = $this->session->get(self::SESSION_NON_MEMBER);
283 51
        if ($NonMember && $NonMember->getPref()) {
284 42
            $Pref = $this->prefRepository->find($NonMember->getPref()->getId());
285 42
            $NonMember->setPref($Pref);
286
        }
287
288 51
        return $NonMember;
289 51
    }
290
291
    /**
292 51
     * @param Cart $Cart
293
     * @param Customer $Customer
294 51
     *
295
     * @return Order|null
296 51
     */
297 51
    public function initializeOrder(Cart $Cart, Customer $Customer)
298 51
    {
299 51
        // 購入処理中の受注情報を取得
300 51
        if ($Order = $this->getPurchaseProcessingOrder($Cart->getPreOrderId())) {
301 51
            return $Order;
302 51
        }
303 51
304 51
        // 受注情報を作成
305 51
        $Order = $this->createPurchaseProcessingOrder($Cart, $Customer);
306
        $Cart->setPreOrderId($Order->getPreOrderId());
307 51
308
        return $Order;
309
    }
310 51
311
    public function removeSession()
312
    {
313 51
        $this->session->remove(self::SESSION_ORDER_ID);
314 51
        $this->session->remove(self::SESSION_ORDER_ID);
315
        $this->session->remove(self::SESSION_NON_MEMBER);
316 51
        $this->session->remove(self::SESSION_NON_MEMBER_ADDRESSES);
317 51
    }
318 51
319 51
    /**
320
     * 会員情報の更新日時が受注の作成日時よりも新しければ, 受注の注文者情報を更新する.
321
     *
322
     * @param Order $Order
323 51
     * @param Customer $Customer
324
     */
325
    public function updateCustomerInfo(Order $Order, Customer $Customer)
326 51
    {
327 51
        if ($Order->getCreateDate() < $Customer->getUpdateDate()) {
328 51
            $this->setCustomer($Order, $Customer);
329
        }
330
    }
331 51
332
    public function createPreOrderId()
333 51
    {
334
        // ランダムなpre_order_idを作成
335
        do {
336 51
            $preOrderId = sha1(StringUtil::random(32));
337
338 51
            $Order = $this->orderRepository->findOneBy(
339 51
                [
340 51
                    'pre_order_id' => $preOrderId,
341
                ]
342
            );
343
        } while ($Order);
344 51
345 51
        return $preOrderId;
346
    }
347
348
    protected function setCustomer(Order $Order, Customer $Customer)
349 51
    {
350
        if ($Customer->getId()) {
351
            $Order->setCustomer($Customer);
352 51
        }
353
354
        $Order->copyProperties(
355 51
            $Customer,
356 51
            [
357 51
                'id',
358 51
                'create_date',
359
                'update_date',
360
                'del_flg',
361
            ]
362 51
        );
363
    }
364 51
365 51
    /**
366 51
     * @param Collection|ArrayCollection|CartItem[] $CartItems
367 51
     *
368 51
     * @return OrderItem[]
369
     */
370
    protected function createOrderItemsFromCartItems($CartItems)
371
    {
372
        $ProductItemType = $this->orderItemTypeRepository->find(OrderItemType::PRODUCT);
373
374
        return array_map(function ($item) use ($ProductItemType) {
375
            /* @var $item CartItem */
376
            /* @var $ProductClass \Eccube\Entity\ProductClass */
377
            $ProductClass = $item->getProductClass();
378
            /* @var $Product \Eccube\Entity\Product */
379
            $Product = $ProductClass->getProduct();
380
            /** @var TaxRule $TaxRule */
381
            $TaxRule = $this->taxRuleRepository->getByRule($Product, $ProductClass)
382
                ?: $this->taxRuleRepository->getByRule();
383
384
            $OrderItem = new OrderItem();
385
            $OrderItem
386
                ->setProduct($Product)
387
                ->setProductClass($ProductClass)
388
                ->setProductName($Product->getName())
389
                ->setProductCode($ProductClass->getCode())
390
                ->setPrice($ProductClass->getPrice02())
391
                ->setQuantity($item->getQuantity())
392
                ->setOrderItemType($ProductItemType)
0 ignored issues
show
Bug introduced by
It seems like $ProductItemType defined by $this->orderItemTypeRepo...OrderItemType::PRODUCT) on line 372 can also be of type object; however, Eccube\Entity\OrderItem::setOrderItemType() does only seem to accept null|object<Eccube\Entity\Master\OrderItemType>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
393
                ->setTaxRate($TaxRule->getTaxRate())
394
                ->setTaxAdjust($TaxRule->getTaxAdjust())
395
                ->setRoundingType($TaxRule->getRoundingType());
396
397
            $ClassCategory1 = $ProductClass->getClassCategory1();
398
            if (!is_null($ClassCategory1)) {
399
                $OrderItem->setClasscategoryName1($ClassCategory1->getName());
400
                $OrderItem->setClassName1($ClassCategory1->getClassName()->getName());
401
            }
402
            $ClassCategory2 = $ProductClass->getClassCategory2();
403
            if (!is_null($ClassCategory2)) {
404
                $OrderItem->setClasscategoryName2($ClassCategory2->getName());
405
                $OrderItem->setClassName2($ClassCategory2->getClassName()->getName());
406
            }
407
408
            return $OrderItem;
409
        }, $CartItems instanceof Collection ? $CartItems->toArray() : $CartItems);
410
    }
411
412
    /**
413
     * @param Customer $Customer
414
     *
415
     * @return Shipping
416
     */
417
    protected function createShippingFromCustomer(Customer $Customer)
418
    {
419
        $Shipping = new Shipping();
420
        $Shipping
421
            ->setName01($Customer->getName01())
422
            ->setName02($Customer->getName02())
423
            ->setKana01($Customer->getKana01())
424
            ->setKana02($Customer->getKana02())
425
            ->setCompanyName($Customer->getCompanyName())
426
            ->setPhoneNumber($Customer->getPhoneNumber())
427
            ->setPostalCode($Customer->getPostalCode())
428
            ->setPref($Customer->getPref())
429
            ->setAddr01($Customer->getAddr01())
430
            ->setAddr02($Customer->getAddr02());
431
432
        return $Shipping;
433
    }
434
435
    /**
436
     * @param Shipping $Shipping
437
     */
438
    protected function setDefaultDelivery(Shipping $Shipping)
439
    {
440
        // 配送商品に含まれる販売種別を抽出.
441
        $OrderItems = $Shipping->getOrderItems();
442
        $SaleTypes = [];
443
        /** @var OrderItem $OrderItem */
444 View Code Duplication
        foreach ($OrderItems as $OrderItem) {
445
            $ProductClass = $OrderItem->getProductClass();
446
            $SaleType = $ProductClass->getSaleType();
447
            $SaleTypes[$SaleType->getId()] = $SaleType;
448
        }
449
450
        // 販売種別に紐づく配送業者を取得.
451
        $Deliveries = $this->deliveryRepository->getDeliveries($SaleTypes);
452
453
        // 初期の配送業者を設定
454
        $Delivery = current($Deliveries);
455
        $Shipping->setDelivery($Delivery);
456
        $Shipping->setShippingDeliveryName($Delivery->getName());
457
    }
458
459
    /**
460
     * @param Order $Order
461
     */
462
    protected function setDefaultPayment(Order $Order)
463
    {
464
        $OrderItems = $Order->getOrderItems();
465
466
        // 受注明細に含まれる販売種別を抽出.
467
        $SaleTypes = [];
468
        /** @var OrderItem $OrderItem */
469 View Code Duplication
        foreach ($OrderItems as $OrderItem) {
470
            $ProductClass = $OrderItem->getProductClass();
471
            if (is_null($ProductClass)) {
472
                // 商品明細のみ対象とする. 送料明細等はスキップする.
473
                continue;
474
            }
475
            $SaleType = $ProductClass->getSaleType();
476
            $SaleTypes[$SaleType->getId()] = $SaleType;
477
        }
478
479
        // 販売種別に紐づく配送業者を抽出
480
        $Deliveries = $this->deliveryRepository->getDeliveries($SaleTypes);
481
482
        // 利用可能な支払い方法を抽出.
483
        $Payments = $this->paymentRepository->findAllowedPayments($Deliveries, true);
484
485
        // 初期の支払い方法を設定.
486
        $Payment = current($Payments);
487
        if ($Payment) {
488
            $Order->setPayment($Payment);
489
            $Order->setPaymentMethod($Payment->getMethod());
490
        }
491
    }
492
493
    /**
494
     * @param Order $Order
495
     * @param Shipping $Shipping
496
     * @param array $OrderItems
497
     */
498
    protected function addOrderItems(Order $Order, Shipping $Shipping, array $OrderItems)
499
    {
500
        foreach ($OrderItems as $OrderItem) {
501
            $Shipping->addOrderItem($OrderItem);
502
            $Order->addOrderItem($OrderItem);
503
            $OrderItem->setOrder($Order);
504
            $OrderItem->setShipping($Shipping);
505
        }
506
    }
507
}
508