Failed Conditions
Pull Request — 4.0 (#3650)
by chihiro
06:14
created

OrderHelper::getNonMember()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 10

Duplication

Lines 10
Ratio 100 %

Code Coverage

Tests 3
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
nc 2
nop 0
dl 10
loc 10
ccs 3
cts 3
cp 1
crap 3
rs 9.9332
c 0
b 0
f 0
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\ORM\EntityManagerInterface;
17
use Eccube\Entity\Cart;
18
use Eccube\Entity\CartItem;
19
use Eccube\Entity\Customer;
20
use Eccube\Entity\Master\DeviceType;
21
use Eccube\Entity\Master\OrderItemType;
22
use Eccube\Entity\Master\OrderStatus;
23
use Eccube\Entity\Order;
24
use Eccube\Entity\OrderItem;
25
use Eccube\Entity\Shipping;
26
use Eccube\EventListener\SecurityListener;
27
use Eccube\Repository\DeliveryRepository;
28
use Eccube\Repository\Master\DeviceTypeRepository;
29
use Eccube\Repository\Master\OrderItemTypeRepository;
30
use Eccube\Repository\Master\OrderStatusRepository;
31
use Eccube\Repository\Master\PrefRepository;
32
use Eccube\Repository\OrderRepository;
33
use Eccube\Repository\PaymentRepository;
34
use Eccube\Util\StringUtil;
35
use SunCat\MobileDetectBundle\DeviceDetector\MobileDetector;
36
use Symfony\Bundle\FrameworkBundle\Controller\ControllerTrait;
37
use Symfony\Component\DependencyInjection\ContainerInterface;
38
use Symfony\Component\HttpFoundation\Session\SessionInterface;
39
40
class OrderHelper
41
{
42
    // FIXME 必要なメソッドのみ移植する
43
    use ControllerTrait;
44
45
    /**
46
     * @var ContainerInterface
47
     */
48
    protected $container;
49
50
    /**
51
     * @var string 非会員情報を保持するセッションのキー
52
     */
53
    const SESSION_NON_MEMBER = 'eccube.front.shopping.nonmember';
54
55
    /**
56
     * @var string 非会員の住所情報を保持するセッションのキー
57
     */
58
    const SESSION_NON_MEMBER_ADDRESSES = 'eccube.front.shopping.nonmember.customeraddress';
59
60
    /**
61
     * @var string 受注IDを保持するセッションのキー
62
     */
63
    const SESSION_ORDER_ID = 'eccube.front.shopping.order.id';
64
65
    /**
66
     * @var string カートが分割されているかどうかのフラグ. 購入フローからのログイン時にカートが分割された場合にtrueがセットされる.
67
     *
68
     * @see SecurityListener
69
     */
70
    const SESSION_CART_DEVIDE_FLAG = 'eccube.front.cart.divide';
71
72
    /**
73
     * @var SessionInterface
74
     */
75
    protected $session;
76
77
    /**
78
     * @var PrefRepository
79
     */
80
    protected $prefRepository;
81
82
    /**
83
     * @var OrderRepository
84
     */
85
    protected $orderRepository;
86
87
    /**
88
     * @var OrderItemTypeRepository
89
     */
90
    protected $orderItemTypeRepository;
91
92
    public function __construct(
93
        ContainerInterface $container,
94
        EntityManagerInterface $entityManager,
95
        OrderRepository $orderRepository,
96
        OrderItemTypeRepository $orderItemTypeRepository,
97
        OrderStatusRepository $orderStatusRepository,
98
        DeliveryRepository $deliveryRepository,
99
        PaymentRepository $paymentRepository,
100
        DeviceTypeRepository $deviceTypeRepository,
101
        PrefRepository $prefRepository,
102
        MobileDetector $mobileDetector,
103
        SessionInterface $session
104
    ) {
105
        $this->container = $container;
106
        $this->orderRepository = $orderRepository;
107
        $this->orderStatusRepository = $orderStatusRepository;
108
        $this->orderItemTypeRepository = $orderItemTypeRepository;
109
        $this->deliveryRepository = $deliveryRepository;
110
        $this->paymentRepository = $paymentRepository;
111
        $this->deviceTypeRepository = $deviceTypeRepository;
112
        $this->entityManager = $entityManager;
113
        $this->prefRepository = $prefRepository;
114
        $this->mobileDetector = $mobileDetector;
115 175
        $this->session = $session;
116
    }
117
118
    /**
119
     * 購入処理中の受注を生成する.
120
     *
121
     * @param Customer $Customer
122
     * @param $CartItems
123
     *
124
     * @return Order
125
     */
126
    public function createPurchaseProcessingOrder(Cart $Cart, Customer $Customer)
127
    {
128 175
        $OrderStatus = $this->orderStatusRepository->find(OrderStatus::PROCESSING);
129 175
        $Order = new Order($OrderStatus);
130 175
131 175
        $preOrderId = $this->createPreOrderId();
132 175
        $Order->setPreOrderId($preOrderId);
133 175
134 175
        // 顧客情報の設定
135 175
        $this->setCustomer($Order, $Customer);
136 175
137 175
        $DeviceType = $this->deviceTypeRepository->find($this->mobileDetector->isMobile() ? DeviceType::DEVICE_TYPE_MB : DeviceType::DEVICE_TYPE_PC);
138 175
        $Order->setDeviceType($DeviceType);
139
140
        // 明細情報の設定
141
        $OrderItems = $this->createOrderItemsFromCartItems($Cart->getCartItems());
0 ignored issues
show
Bug introduced by
It seems like $Cart->getCartItems() targeting Eccube\Entity\Cart::getCartItems() can also be of type object<Doctrine\Common\Collections\Collection>; however, Eccube\Service\OrderHelp...derItemsFromCartItems() does only seem to accept object<Eccube\Service\Ar...ccube\Entity\CartItem>>, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
142
        $OrderItemsGroupBySaleType = array_reduce($OrderItems, function ($result, $item) {
143
            /* @var OrderItem $item */
144
            $saleTypeId = $item->getProductClass()->getSaleType()->getId();
145
            $result[$saleTypeId][] = $item;
146
147
            return $result;
148
        }, []);
149 51
150
        foreach ($OrderItemsGroupBySaleType as $OrderItems) {
151 51
            $Shipping = $this->createShippingFromCustomer($Customer);
152 51
            $Shipping->setOrder($Order);
153
            $this->addOrderItems($Order, $Shipping, $OrderItems);
154 51
            $this->setDefaultDelivery($Shipping);
155
            $this->entityManager->persist($Shipping);
156 51
            $Order->addShipping($Shipping);
157
        }
158
159
        $this->setDefaultPayment($Order);
160 51
161
        $this->entityManager->persist($Order);
162 51
163 51
        return $Order;
164
    }
165
166 51
    /**
167 51
     * @param Cart|null $Cart
168
     * @return bool
169 51
     */
170 51
    public function verifyCart(Cart $Cart = null)
171
    {
172 51
        if ($Cart && count($Cart->getCartItems()) > 0) {
173 51
            $divide = $this->session->get(self::SESSION_CART_DEVIDE_FLAG);
174
            if ($divide) {
175 51
                log_info('ログイン時に販売種別が異なる商品がカートと結合されました。');
176 51
177 51
                return false;
178 51
            }
179 51
180 51
            return true;
181 51
        }
182
183
        log_info('カートに商品が入っていません。');
184 51
185
        return false;
186 51
    }
187
188
    /**
189 51
     * 注文手続き画面でログインが必要かどうかの判定
190
     *
191
     * @return bool
192
     */
193
    public function isLoginRequired()
194
    {
195
        // フォームログイン済はログイン不要
196
        if ($this->isGranted('IS_AUTHENTICATED_FULLY')) {
197
            return false;
198
        }
199 2
200
        // Remember Meログイン済の場合はフォームからのログインが必要
201 2
        if ($this->isGranted('IS_AUTHENTICATED_REMEMBERED')) {
202 2
            return true;
203
        }
204 2
205 1
        // 未ログインだがお客様情報を入力している場合はログイン不要
206 1
        if (!$this->getUser() && $this->getNonMember()) {
207 1
            return false;
208 1
        }
209 1
210 1
        return true;
211 1
    }
212
213
    /**
214 2
     * 購入処理中の受注を取得する.
215
     *
216
     * @param null|string $preOrderId
217 51
     *
218
     * @return null|Order
219
     */
220
    public function getPurchaseProcessingOrder($preOrderId = null)
221 51
    {
222
        if (null === $preOrderId) {
223 51
            return null;
224
        }
225 51
226
        return $this->orderRepository->findOneBy([
227
            'pre_order_id' => $preOrderId,
228
            'OrderStatus' => OrderStatus::PROCESSING,
229 51
        ]);
230
    }
231 51
232
    /**
233
     * セッションに保持されている非会員情報を取得する.
234 51
     * 非会員購入時に入力されたお客様情報を返す.
235
     *
236 51
     * @return Customer
237 34
     */
238 View Code Duplication
    public function getNonMember()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
239
    {
240 51
        $NonMember = $this->session->get(self::SESSION_NON_MEMBER);
241 51
        if ($NonMember && $NonMember->getPref()) {
242
            $Pref = $this->prefRepository->find($NonMember->getPref()->getId());
243 51
            $NonMember->setPref($Pref);
244
        }
245
246
        return $NonMember;
247
    }
248
249
    /**
250
     * @param Cart $Cart
251
     * @param Customer $Customer
252
     *
253
     * @return Order|null
254
     */
255
    public function initializeOrder(Cart $Cart, Customer $Customer)
256 51
    {
257
        // 購入処理中の受注情報を取得
258 51
        if ($Order = $this->getPurchaseProcessingOrder($Cart->getPreOrderId())) {
259
            return $Order;
260 51
        }
261
262
        // 受注情報を作成
263 51
        $Order = $this->createPurchaseProcessingOrder($Cart, $Customer);
264
        $Cart->setPreOrderId($Order->getPreOrderId());
265 51
266
        return $Order;
267 51
    }
268
269 51
    public function removeSession()
270 51
    {
271 51
        $this->session->remove(self::SESSION_ORDER_ID);
272 51
        $this->session->remove(self::SESSION_ORDER_ID);
273 51
        $this->session->remove(self::SESSION_NON_MEMBER);
274 51
        $this->session->remove(self::SESSION_NON_MEMBER_ADDRESSES);
275 51
    }
276
277 51
    private function createPreOrderId()
278 51
    {
279 51
        // ランダムなpre_order_idを作成
280 51
        do {
281
            $preOrderId = sha1(StringUtil::random(32));
282 51
283 51
            $Order = $this->orderRepository->findOneBy(
284 42
                [
285 42
                    'pre_order_id' => $preOrderId,
286
                    'OrderStatus' => OrderStatus::PROCESSING,
287
                ]
288 51
            );
289 51
        } while ($Order);
290
291
        return $preOrderId;
292 51
    }
293
294 51
    private function setCustomer(Order $Order, Customer $Customer)
295
    {
296 51
        if ($Customer->getId()) {
297 51
            $Order->setCustomer($Customer);
298 51
        }
299 51
300 51
        $Order->copyProperties(
301 51
            $Customer,
302 51
            [
303 51
                'id',
304 51
                'create_date',
305 51
                'update_date',
306
                'del_flg',
307 51
            ]
308
        );
309
    }
310 51
311
    /**
312
     * @param ArrayCollection|CartItem[] $CartItems
313 51
     *
314 51
     * @return OrderItem[]
315
     */
316 51
    private function createOrderItemsFromCartItems($CartItems)
317 51
    {
318 51
        $ProductItemType = $this->orderItemTypeRepository->find(OrderItemType::PRODUCT);
319 51
320
        return array_map(function ($item) use ($ProductItemType) {
321
            /* @var $item CartItem */
322
            /* @var $ProductClass \Eccube\Entity\ProductClass */
323 51
            $ProductClass = $item->getProductClass();
324
            /* @var $Product \Eccube\Entity\Product */
325
            $Product = $ProductClass->getProduct();
326 51
327 51
            $OrderItem = new OrderItem();
328 51
            $OrderItem
329
                ->setProduct($Product)
330
                ->setProductClass($ProductClass)
331 51
                ->setProductName($Product->getName())
332
                ->setProductCode($ProductClass->getCode())
333 51
                ->setPrice($ProductClass->getPrice02())
334
                ->setQuantity($item->getQuantity())
335
                ->setOrderItemType($ProductItemType);
0 ignored issues
show
Bug introduced by
It seems like $ProductItemType defined by $this->orderItemTypeRepo...OrderItemType::PRODUCT) on line 318 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...
336 51
337
            $ClassCategory1 = $ProductClass->getClassCategory1();
338 51
            if (!is_null($ClassCategory1)) {
339 51
                $OrderItem->setClasscategoryName1($ClassCategory1->getName());
340 51
                $OrderItem->setClassName1($ClassCategory1->getClassName()->getName());
341
            }
342
            $ClassCategory2 = $ProductClass->getClassCategory2();
343
            if (!is_null($ClassCategory2)) {
344 51
                $OrderItem->setClasscategoryName2($ClassCategory2->getName());
345 51
                $OrderItem->setClassName2($ClassCategory2->getClassName()->getName());
346
            }
347
348
            return $OrderItem;
349 51
        }, $CartItems->toArray());
350
    }
351
352 51
    /**
353
     * @param Customer $Customer
354
     *
355 51
     * @return Shipping
356 51
     */
357 51
    private function createShippingFromCustomer(Customer $Customer)
358 51
    {
359
        $Shipping = new Shipping();
360
        $Shipping
361
            ->setName01($Customer->getName01())
362 51
            ->setName02($Customer->getName02())
363
            ->setKana01($Customer->getKana01())
364 51
            ->setKana02($Customer->getKana02())
365 51
            ->setCompanyName($Customer->getCompanyName())
366 51
            ->setPhoneNumber($Customer->getPhoneNumber())
367 51
            ->setPostalCode($Customer->getPostalCode())
368 51
            ->setPref($Customer->getPref())
369
            ->setAddr01($Customer->getAddr01())
370
            ->setAddr02($Customer->getAddr02());
371
372
        return $Shipping;
373
    }
374
375
    /**
376
     * @param Shipping $Shipping
377
     */
378
    private function setDefaultDelivery(Shipping $Shipping)
379
    {
380
        // 配送商品に含まれる販売種別を抽出.
381
        $OrderItems = $Shipping->getOrderItems();
382
        $SaleTypes = [];
383
        /** @var OrderItem $OrderItem */
384 View Code Duplication
        foreach ($OrderItems as $OrderItem) {
385
            $ProductClass = $OrderItem->getProductClass();
386
            $SaleType = $ProductClass->getSaleType();
387
            $SaleTypes[$SaleType->getId()] = $SaleType;
388
        }
389
390
        // 販売種別に紐づく配送業者を取得.
391
        $Deliveries = $this->deliveryRepository->getDeliveries($SaleTypes);
392
393
        // 初期の配送業者を設定
394
        $Delivery = current($Deliveries);
395
        $Shipping->setDelivery($Delivery);
396
        $Shipping->setShippingDeliveryName($Delivery->getName());
397
    }
398
399
    /**
400
     * @param Order $Order
401
     */
402
    private function setDefaultPayment(Order $Order)
403
    {
404
        $OrderItems = $Order->getOrderItems();
405
406
        // 受注明細に含まれる販売種別を抽出.
407
        $SaleTypes = [];
408
        /** @var OrderItem $OrderItem */
409 View Code Duplication
        foreach ($OrderItems as $OrderItem) {
410
            $ProductClass = $OrderItem->getProductClass();
411
            if (is_null($ProductClass)) {
412
                // 商品明細のみ対象とする. 送料明細等はスキップする.
413
                continue;
414
            }
415
            $SaleType = $ProductClass->getSaleType();
416
            $SaleTypes[$SaleType->getId()] = $SaleType;
417
        }
418
419
        // 販売種別に紐づく配送業者を抽出
420
        $Deliveries = $this->deliveryRepository->getDeliveries($SaleTypes);
421
422
        // 利用可能な支払い方法を抽出.
423
        $Payments = $this->paymentRepository->findAllowedPayments($Deliveries, true);
424
425
        // 初期の支払い方法を設定.
426
        $Payment = current($Payments);
427
        if ($Payment) {
428
            $Order->setPayment($Payment);
429
            $Order->setPaymentMethod($Payment->getMethod());
430
        }
431
    }
432
433
    /**
434
     * @param Order $Order
435
     * @param Shipping $Shipping
436
     * @param array $OrderItems
437
     */
438
    private function addOrderItems(Order $Order, Shipping $Shipping, array $OrderItems)
439
    {
440
        foreach ($OrderItems as $OrderItem) {
441
            $Shipping->addOrderItem($OrderItem);
442
            $Order->addOrderItem($OrderItem);
443
            $OrderItem->setOrder($Order);
444
            $OrderItem->setShipping($Shipping);
445
        }
446
    }
447
}
448