Completed
Pull Request — 4.0 (#3767)
by chihiro
23:02
created

OrderHelper::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 25

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1

Importance

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