Completed
Push — 4.0 ( 6044ef...5d8c02 )
by Kiyotaka
08:42 queued 04:03
created

OrderHelper::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 25

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 1

Importance

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