Completed
Pull Request — experimental/sf (#3439)
by
unknown
445:38 queued 438:22
created

ShoppingController::confirm()   C

Complexity

Conditions 13
Paths 9

Size

Total Lines 64

Duplication

Lines 9
Ratio 14.06 %

Code Coverage

Tests 19
CRAP Score 27.5142

Importance

Changes 0
Metric Value
cc 13
nc 9
nop 1
dl 9
loc 64
ccs 19
cts 34
cp 0.5588
crap 27.5142
rs 6.0787
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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\Controller;
15
16
use Eccube\Annotation\ForwardOnly;
17
use Eccube\Entity\BaseInfo;
18
use Eccube\Entity\Customer;
19
use Eccube\Entity\CustomerAddress;
20
use Eccube\Entity\Master\OrderStatus;
21
use Eccube\Entity\Order;
22
use Eccube\Entity\Shipping;
23
use Eccube\Event\EccubeEvents;
24
use Eccube\Event\EventArgs;
25
use Eccube\Exception\CartException;
26
use Eccube\Exception\ShoppingException;
27
use Eccube\Form\Type\Front\CustomerLoginType;
28
use Eccube\Form\Type\Front\ShoppingShippingType;
29
use Eccube\Form\Type\Shopping\CustomerAddressType;
30
use Eccube\Form\Type\Shopping\OrderType;
31
use Eccube\Repository\CustomerAddressRepository;
32
use Eccube\Repository\OrderRepository;
33
use Eccube\Service\CartService;
34
use Eccube\Service\OrderHelper;
35
use Eccube\Service\Payment\PaymentDispatcher;
36
use Eccube\Service\ShoppingService;
37
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
38
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
39
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
40
use Symfony\Component\Form\FormError;
41
use Symfony\Component\Form\FormInterface;
42
use Symfony\Component\HttpFoundation\ParameterBag;
43
use Symfony\Component\HttpFoundation\Request;
44
use Symfony\Component\HttpFoundation\Response;
45
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
46
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
47
48
class ShoppingController extends AbstractShoppingController
49
{
50
    /**
51
     * @var BaseInfo
52
     */
53
    protected $BaseInfo;
54
55
    /**
56
     * @var OrderHelper
57
     */
58
    protected $orderHelper;
59
60
    /**
61
     * @var CartService
62
     */
63
    protected $cartService;
64
65
    /**
66
     * @var ShoppingService
67
     */
68
    protected $shoppingService;
69
70
    /**
71
     * @var CustomerAddressRepository
72
     */
73
    protected $customerAddressRepository;
74
75
    /**
76
     * @var ParameterBag
77
     */
78
    protected $parameterBag;
79
80
    /**
81
     * ShoppingController constructor.
82
     *
83
     * @param BaseInfo $BaseInfo
84
     * @param OrderHelper $orderHelper
85
     * @param CartService $cartService
86
     * @param ShoppingService $shoppingService
87
     * @param CustomerAddressRepository $customerAddressRepository
88
     * @param ParameterBag $parameterBag
89
     */
90 59
    public function __construct(
91
        BaseInfo $BaseInfo,
92
        OrderHelper $orderHelper,
93
        CartService $cartService,
94
        ShoppingService $shoppingService,
95
        CustomerAddressRepository $customerAddressRepository,
96
        OrderRepository $orderRepository,
97
        ParameterBag $parameterBag
98
    ) {
99 59
        $this->BaseInfo = $BaseInfo;
100 59
        $this->orderHelper = $orderHelper;
101 59
        $this->cartService = $cartService;
102 59
        $this->shoppingService = $shoppingService;
103 59
        $this->customerAddressRepository = $customerAddressRepository;
104 59
        $this->orderRepository = $orderRepository;
105 59
        $this->parameterBag = $parameterBag;
106
    }
107
108
    /**
109
     * 購入画面表示
110
     *
111
     * @Route("/shopping", name="shopping")
112
     * @Template("Shopping/index.twig")
113
     */
114 51
    public function index(Request $request)
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
115
    {
116
        // カートチェック
117 51
        $response = $this->forwardToRoute('shopping_check_to_cart');
118 51
        if ($response->isRedirection() || $response->getContent()) {
119 1
            return $response;
120
        }
121
122
        // 受注情報を初期化
123 50
        $response = $this->forwardToRoute('shopping_initialize_order');
124 50
        if ($response->isRedirection() || $response->getContent()) {
125
            return $response;
126
        }
127
128
        /** @var Order $Order */
129 50
        $Order = $this->parameterBag->get('Order');
130
131
        // 単価集計
132 50
        $flowResult = $this->validatePurchaseFlow($Order);
133
134
        // 明細が丸められる場合に, カートから注文画面へ遷移できなくなるため, 集計の結果を保存する
135 50
        $this->entityManager->flush();
136
137
        // フォームを生成する
138 50
        $this->forwardToRoute('shopping_create_form');
139
140 50
        if ($flowResult->hasWarning() || $flowResult->hasError()) {
141 10
            return $this->redirectToRoute('cart');
142
        }
143
144 45
        $form = $this->parameterBag->get(OrderType::class);
145
146
        return [
147 45
            'form' => $form->createView(),
148 45
            'Order' => $Order,
149
        ];
150
    }
151
152
    /**
153
     * 購入確認画面から, 他の画面へのリダイレクト.
154
     * 配送業者や支払方法、お問い合わせ情報をDBに保持してから遷移する.
155
     *
156
     * @Route("/shopping/redirect", name="shopping_redirect_to")
157
     * @Template("Shopping/index.twig")
158
     */
159 20
    public function redirectTo(Request $request)
160
    {
161
        // カートチェック
162 20
        $response = $this->forwardToRoute('shopping_check_to_cart');
163 20
        if ($response->isRedirection() || $response->getContent()) {
164
            return $response;
165
        }
166
167
        // 受注の存在チェック
168 20
        $response = $this->forwardToRoute('shopping_exists_order');
169 20
        if ($response->isRedirection() || $response->getContent()) {
170
            return $response;
171
        }
172
173
        // フォームの生成
174 20
        $this->forwardToRoute('shopping_create_form');
175
        /** @var FormInterface $form */
176 20
        $form = $this->parameterBag->get(OrderType::class);
177 20
        $form->handleRequest($request);
178
179
        // valid form
180 20 View Code Duplication
        if ($form->isSubmitted() && !$form->isValid()) {
181 11
            $this->parameterBag->set(OrderType::class, $form);
182 11
            $Order = $this->parameterBag->get('Order');
183
184
            return [
185 11
                'form' => $form->createView(),
186 11
                'Order' => $Order,
187
            ];
188
        }
189
190
        // 各種変更ページへリダイレクトする
191 9
        $response = $this->forwardToRoute('shopping_redirect_to_change');
192 9
        if ($response->isRedirection() || $response->getContent()) {
193 8
            return $response;
194
        }
195 1
        $form = $this->parameterBag->get(OrderType::class);
196 1
        $Order = $this->parameterBag->get('Order');
197
198
        return [
199 1
            'form' => $form->createView(),
200 1
            'Order' => $Order,
201
        ];
202
    }
203
204
    /**
205
     * 購入処理
206
     *
207
     * @Route("/shopping/confirm", name="shopping_confirm")
208
     * @Method("POST")
209
     * @Template("Shopping/confirm.twig")
210
     */
211 5
    public function confirm(Request $request)
212
    {
213
        // カートチェック
214 5
        $response = $this->forwardToRoute('shopping_check_to_cart');
215 5
        if ($response->isRedirection() || $response->getContent()) {
216
            return $response;
217
        }
218
219
        // 受注の存在チェック
220 5
        $response = $this->forwardToRoute('shopping_exists_order');
221 5
        if ($response->isRedirection() || $response->getContent()) {
222
            return $response;
223
        }
224
225
        // フォームの生成
226 5
        $this->forwardToRoute('shopping_create_form');
227
        /** @var FormInterface $form */
228 5
        $form = $this->parameterBag->get(OrderType::class);
229 5
        $form->handleRequest($request);
230
231
        // valid form
232 5 View Code Duplication
        if (!$form->isValid()) {
233
            $this->parameterBag->set(OrderType::class, $form);
234
            $Order = $this->parameterBag->get('Order');
235
236
            return $this->render('Shopping/index.twig', [
237
                'form' => $form->createView(),
238
                'Order' => $Order,
239
            ]);
240
        }
241
242 5
        $form = $this->parameterBag->get(OrderType::class);
243 5
        $Order = $this->parameterBag->get('Order');
244
245 5
        $flowResult = $this->validatePurchaseFlow($Order);
246 5
        if ($flowResult->hasWarning() || $flowResult->hasError()) {
247
            return $this->redirectToRoute('shopping_error');
248
        }
249
250 5
        $paymentMethod = $this->createPaymentMethod($Order, $form);
251
252 5
        $PaymentResult = $paymentMethod->verify();
253
        // エラーの場合は注文入力画面に戻す?
254 5
        if ($PaymentResult instanceof PaymentResult) {
255
            if (!$PaymentResult->isSuccess()) {
256
                $this->entityManager->getConnection()->rollback();
257
258
                $this->addError($PaymentResult->getErrors());
259
            }
260
261
            $response = $PaymentResult->getResponse();
262
            if ($response && ($response->isRedirection() || $response->getContent())) {
263
                $this->entityManager->flush();
264
265
                return $response;
266
            }
267
        }
268 5
        $this->entityManager->flush();
269
270
        return [
271 5
            'form' => $form->createView(),
272 5
            'Order' => $Order,
273
        ];
274
    }
275
276
    /**
277
     * 購入処理
278
     *
279
     * @Route("/shopping/order", name="shopping_order")
280
     * @Method("POST")
281
     * @Template("Shopping/index.twig")
282
     */
283 6
    public function order(Request $request)
284
    {
285
        // カートチェック
286 6
        $response = $this->forwardToRoute('shopping_check_to_cart');
287 6
        if ($response->isRedirection() || $response->getContent()) {
288
            return $response;
289
        }
290
291
        // 受注の存在チェック
292 6
        $response = $this->forwardToRoute('shopping_exists_order');
293 6
        if ($response->isRedirection() || $response->getContent()) {
294
            return $response;
295
        }
296
297
        // form作成
298
        // FIXME イベントハンドラを外から渡したい
299 6
        $this->forwardToRoute('shopping_create_form');
300
301 6
        $form = $this->parameterBag->get(OrderType::class);
302 6
        $Order = $this->parameterBag->get('Order');
303 6
        $usePoint = $Order->getUsePoint();
304
305 6
        $form->handleRequest($request);
306 6
        $Order->setUsePoint($usePoint);
307
308
        // 受注処理
309 6
        $response = $this->forwardToRoute('shopping_complete_order');
310 6
        if ($response->isRedirection() || $response->getContent()) {
311 6
            return $response;
312
        }
313
314
        log_info('購入チェックエラー', [$Order->getId()]);
315
316
        return [
317
            'form' => $form->createView(),
318
            'Order' => $Order,
319
        ];
320
    }
321
322
    /**
323
     * 支払方法バーリデト
324
     */
325
    private function isValidPayment(Application $app, $form)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
326
    {
327
        $data = $form->getData();
328
        $paymentId = $data['payment']->getId();
329
        $shippings = $data['shippings'];
330
        $validCount = count($shippings);
331
        foreach ($shippings as $Shipping) {
332
            $payments = $app['eccube.repository.payment']->findPayments($Shipping->getDelivery());
333
            if ($payments == null) {
334
                continue;
335
            }
336
            foreach ($payments as $payment) {
337
                if ($payment['id'] == $paymentId) {
338
                    $validCount--;
339
                    continue;
340
                }
341
            }
342
        }
343
        if ($validCount == 0) {
344
            return true;
345
        }
346
        $form->get('payment')->addError(new FormError('front.shopping.payment.error'));
347
348
        return false;
349
    }
350
351
    /**
352
     * 購入完了画面表示
353
     *
354
     * @Route("/shopping/complete", name="shopping_complete")
355
     * @Template("Shopping/complete.twig")
356
     */
357 1
    public function complete(Request $request)
358
    {
359
        // 受注IDを取得
360 1
        $orderId = $this->session->get($this->sessionOrderKey);
361
362 1
        if (empty($orderId)) {
363
            return $this->redirectToRoute('homepage');
364
        }
365
366 1
        $Order = $this->orderRepository->find($orderId);
367
368 1
        $event = new EventArgs(
369
            [
370 1
                'Order' => $Order,
371
            ],
372 1
            $request
373
        );
374 1
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_SHOPPING_COMPLETE_INITIALIZE, $event);
375
376 1
        if ($event->getResponse() !== null) {
377
            return $event->getResponse();
378
        }
379
380
        // 受注に関連するセッションを削除
381 1
        $this->session->remove($this->sessionOrderKey);
382 1
        $this->session->remove($this->sessionKey);
383 1
        $this->session->remove($this->sessionCustomerAddressKey);
384
385 1
        log_info('購入処理完了', [$Order->getId()]);
386
387 1
        $hasNextCart = !empty($this->cartService->getCarts());
388
389
        return [
390 1
            'Order' => $Order,
391 1
            'hasNextCart' => $hasNextCart,
392
        ];
393
    }
394
395
    /**
396
     * お届け先の設定一覧からの選択
397
     *
398
     * @Route("/shopping/shipping/{id}", name="shopping_shipping", requirements={"id" = "\d+"})
399
     * @Template("Shopping/shipping.twig")
400
     */
401
    public function shipping(Request $request, Shipping $Shipping)
402
    {
403
        // カートチェック
404
        $response = $this->forwardToRoute('shopping_check_to_cart');
405
        if ($response->isRedirection() || $response->getContent()) {
406
            return $response;
407
        }
408
409
        // 受注の存在チェック
410
        $response = $this->forwardToRoute('shopping_exists_order');
411
        if ($response->isRedirection() || $response->getContent()) {
412
            return $response;
413
        }
414
415
        // 受注に紐づくShippingかどうかのチェック.
416
        /** @var Order $Order */
417
        $Order = $this->parameterBag->get('Order');
418
        if (!$Order->findShipping($Shipping->getId())) {
419
            throw new NotFoundHttpException();
420
        }
421
422
        $builder = $this->formFactory->createBuilder(CustomerAddressType::class, null, [
423
            'customer' => $this->getUser(),
424
            'shipping' => $Shipping,
425
        ]);
426
427
        $form = $builder->getForm();
428
        $form->handleRequest($request);
429
430
        if ($form->isSubmitted() && $form->isValid()) {
431
            log_info('お届先情報更新開始', [$Shipping->getId()]);
432
433
            /** @var CustomerAddress $CustomerAddress */
434
            $CustomerAddress = $form['addresses']->getData();
435
436
            // お届け先情報を更新
437
            $Shipping->setFromCustomerAddress($CustomerAddress);
438
439
            // 合計金額の再計算
440
            $flowResult = $this->validatePurchaseFlow($Order);
441
            if ($flowResult->hasWarning() || $flowResult->hasError()) {
442
                return $this->redirectToRoute('shopping_error');
443
            }
444
445
            // 配送先を更新
446
            $this->entityManager->flush();
447
448
            $event = new EventArgs(
449
                [
450
                    'Order' => $Order,
451
                    'Shipping' => $Shipping,
452
                ],
453
                $request
454
            );
455
            $this->eventDispatcher->dispatch(EccubeEvents::FRONT_SHOPPING_SHIPPING_COMPLETE, $event);
456
457
            log_info('お届先情報更新完了', [$Shipping->getId()]);
458
459
            return $this->redirectToRoute('shopping');
460
        }
461
462
        return [
463
            'form' => $form->createView(),
464
            'Customer' => $this->getUser(),
465
            'shippingId' => $Shipping->getId(),
466
        ];
467
    }
468
469
    /**
470
     * お届け先の設定(非会員でも使用する)
471
     *
472
     * @Route("/shopping/shipping_edit/{id}", name="shopping_shipping_edit", requirements={"id" = "\d+"})
473
     * @Template("Shopping/shipping_edit.twig")
474
     */
475
    public function shippingEdit(Request $request, $id)
476
    {
477
        // 配送先住所最大値判定
478
        $Customer = $this->getUser();
479
        if ($this->isGranted('IS_AUTHENTICATED_FULLY')) {
480
            $addressCurrNum = count($this->getUser()->getCustomerAddresses());
481
            $addressMax = $this->eccubeConfig['eccube_deliv_addr_max'];
482
            if ($addressCurrNum >= $addressMax) {
483
                throw new NotFoundHttpException(trans('shoppingcontroller.text.error.number_of_address'));
484
            }
485
        }
486
487
        // カートチェック
488
        $response = $this->forwardToRoute('shopping_check_to_cart');
489
        if ($response->isRedirection() || $response->getContent()) {
490
            return $response;
491
        }
492
493
        // 受注の存在チェック
494
        $response = $this->forwardToRoute('shopping_exists_order');
495
        if ($response->isRedirection() || $response->getContent()) {
496
            return $response;
497
        }
498
499
        /** @var Order $Order */
500
        $Order = $this->parameterBag->get('Order');
501
502
        $Shipping = $Order->findShipping($id);
503
        if (!$Shipping) {
504
            throw new NotFoundHttpException(trans('shoppingcontroller.text.error.set_address'));
505
        }
506
        if ($this->isGranted('IS_AUTHENTICATED_FULLY')) {
507
            $Shipping->clearCustomerAddress();
508
        }
509
510
        $CustomerAddress = new CustomerAddress();
511
        if ($this->isGranted('IS_AUTHENTICATED_FULLY')) {
512
            $CustomerAddress->setCustomer($Customer);
0 ignored issues
show
Bug introduced by
It seems like $Customer defined by $this->getUser() on line 478 can also be of type object; however, Eccube\Entity\CustomerAddress::setCustomer() does only seem to accept null|object<Eccube\Entity\Customer>, 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...
513
        } else {
514
            $CustomerAddress->setFromShipping($Shipping);
515
        }
516
517
        $builder = $this->formFactory->createBuilder(ShoppingShippingType::class, $CustomerAddress);
518
519
        $event = new EventArgs(
520
            [
521
                'builder' => $builder,
522
                'Order' => $Order,
523
                'Shipping' => $Shipping,
524
                'CustomerAddress' => $CustomerAddress,
525
            ],
526
            $request
527
        );
528
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_SHOPPING_SHIPPING_EDIT_INITIALIZE, $event);
529
530
        $form = $builder->getForm();
531
532
        $form->handleRequest($request);
533
534
        if ($form->isSubmitted() && $form->isValid()) {
535
            log_info('お届け先追加処理開始', ['id' => $Order->getId(), 'shipping' => $id]);
536
537
            // 会員の場合、お届け先情報を新規登録
538
            $Shipping->setFromCustomerAddress($CustomerAddress);
539
540
            if ($Customer instanceof Customer) {
541
                $this->entityManager->persist($CustomerAddress);
542
                log_info(
543
                    '新規お届け先登録',
544
                    [
545
                        'id' => $Order->getId(),
546
                        'shipping' => $id,
547
                        'customer address' => $CustomerAddress->getId(),
548
                    ]
549
                );
550
            }
551
552
            // 配送料金の設定
553
            $this->shoppingService->setShippingDeliveryFee($Shipping);
554
555
            // 合計金額の再計算
556
            $flowResult = $this->validatePurchaseFlow($Order);
557
            if ($flowResult->hasWarning() || $flowResult->hasError()) {
558
                return $this->redirectToRoute('shopping_error');
559
            }
560
561
            // 配送先を更新
562
            $this->entityManager->flush();
563
564
            $event = new EventArgs(
565
                [
566
                    'form' => $form,
567
                    'Shipping' => $Shipping,
568
                    'CustomerAddress' => $CustomerAddress,
569
                ],
570
                $request
571
            );
572
            $this->eventDispatcher->dispatch(EccubeEvents::FRONT_SHOPPING_SHIPPING_EDIT_COMPLETE, $event);
573
574
            log_info('お届け先追加処理完了', ['id' => $Order->getId(), 'shipping' => $id]);
575
576
            return $this->redirectToRoute('shopping');
577
        }
578
579
        return [
580
            'form' => $form->createView(),
581
            'shippingId' => $id,
582
        ];
583
    }
584
585
    /**
586
     * ログイン
587
     *
588
     * @Route("/shopping/login", name="shopping_login")
589
     * @Template("Shopping/login.twig")
590
     */
591 2
    public function login(Request $request, AuthenticationUtils $authenticationUtils)
592
    {
593 2
        if ($this->isGranted('IS_AUTHENTICATED_FULLY')) {
594
            return $this->redirectToRoute('shopping');
595
        }
596
597
        /* @var $form \Symfony\Component\Form\FormInterface */
598 2
        $builder = $this->formFactory->createNamedBuilder('', CustomerLoginType::class);
599
600 2
        if ($this->isGranted('IS_AUTHENTICATED_REMEMBERED')) {
601
            $Customer = $this->getUser();
602
            if ($Customer) {
603
                $builder->get('login_email')->setData($Customer->getEmail());
604
            }
605
        }
606
607 2
        $event = new EventArgs(
608
            [
609 2
                'builder' => $builder,
610
            ],
611 2
            $request
612
        );
613 2
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_SHOPPING_LOGIN_INITIALIZE, $event);
614
615 2
        $form = $builder->getForm();
616
617
        return [
618 2
            'error' => $authenticationUtils->getLastAuthenticationError(),
619 2
            'form' => $form->createView(),
620
        ];
621
    }
622
623
    /**
624
     * 購入エラー画面表示
625
     *
626
     * @Route("/shopping/error", name="shopping_error")
627
     * @Template("Shopping/shopping_error.twig")
628
     */
629 1
    public function shoppingError(Request $request)
630
    {
631 1
        $event = new EventArgs(
632 1
            [],
633 1
            $request
634
        );
635 1
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_SHOPPING_SHIPPING_ERROR_COMPLETE, $event);
636
637 1
        if ($event->getResponse() !== null) {
638
            return $event->getResponse();
639
        }
640
641 1
        return [];
642
    }
643
644
    /**
645
     * カート画面のチェック
646
     *
647
     * @ForwardOnly
648
     * @Route("/shopping/check_to_cart", name="shopping_check_to_cart")
649
     */
650 55
    public function checkToCart(Request $request)
651
    {
652 55
        $Cart = $this->cartService->getCart();
653 55
        if ($Cart && count($Cart->getCartItems()) > 0) {
654 53
            $divide = $request->getSession()->get('cart.divide');
655 53
            if ($divide) {
656
                log_info('種別が異なる商品がカートと結合されたためカート画面にリダイレクト');
657
658
                return $this->redirectToRoute('cart');
659
            }
660
661 53
            return new Response();
662
        }
663 2
        log_info('カートに商品が入っていないためショッピングカート画面にリダイレクト');
664
665
        // カートが存在しない時はエラー
666 2
        return $this->redirectToRoute('cart');
667
    }
668
669
    /**
670
     * 受注情報を初期化する.
671
     *
672
     * @ForwardOnly
673
     * @Route("/shopping/initialize_order", name="shopping_initialize_order")
674
     */
675 50
    public function initializeOrder(Request $request)
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
676
    {
677
        // 購入処理中の受注情報を取得
678 50
        $Order = $this->shoppingService->getOrder(OrderStatus::PROCESSING);
679
680
        // 初回アクセス(受注情報がない)の場合は, 受注情報を作成
681 50
        if (is_null($Order)) {
682
            // 未ログインの場合, ログイン画面へリダイレクト.
683 34
            if (!$this->isGranted('IS_AUTHENTICATED_FULLY')) {
684
                // 非会員でも一度会員登録されていればショッピング画面へ遷移
685
                $Customer = $this->shoppingService->getNonMember($this->sessionKey);
686
687
                if (is_null($Customer)) {
688
                    log_info('未ログインのためログイン画面にリダイレクト');
689
690
                    return $this->redirectToRoute('shopping_login');
691
                }
692
            } else {
693 34
                $Customer = $this->getUser();
694
            }
695
696
            try {
697
                // 受注情報を作成
698
                //$Order = $app['eccube.service.shopping']->createOrder($Customer);
699 34
                $Order = $this->orderHelper->createProcessingOrder(
700 34
                    $Customer,
701 34
                    $this->cartService->getCart()->getCartItems()
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Eccube\Entity\ItemHolderInterface as the method getCartItems() does only exist in the following implementations of said interface: Eccube\Entity\Cart.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
702
                );
703 34
                $this->cartService->setPreOrderId($Order->getPreOrderId());
704 34
                $this->cartService->save();
705
            } catch (CartException $e) {
706
                log_error('初回受注情報作成エラー', [$e->getMessage()]);
707
                $this->addRequestError($e->getMessage());
708
709
                return $this->redirectToRoute('cart');
710
            }
711
712
            // セッション情報を削除
713 34
            $this->session->remove($this->sessionOrderKey);
714
        }
715
716
        // 受注関連情報を最新状態に更新
717 50
        $this->entityManager->refresh($Order);
718
719 50
        $this->parameterBag->set('Order', $Order);
720
721 50
        return new Response();
722
    }
723
724
    /**
725
     * フォームを作成し, イベントハンドラを設定する
726
     *
727
     * @ForwardOnly
728
     * @Route("/shopping/create_form", name="shopping_create_form")
729
     */
730 50
    public function createShoppingForm(Request $request)
731
    {
732 50
        $Order = $this->parameterBag->get('Order');
733
        // フォームの生成
734 50
        $builder = $this->formFactory->createBuilder(OrderType::class, $Order);
735
736 50
        $event = new EventArgs(
737
                [
738 50
                    'builder' => $builder,
739 50
                    'Order' => $Order,
740
                ],
741 50
                $request
742
            );
743 50
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_SHOPPING_INDEX_INITIALIZE, $event);
744
745 50
        $form = $builder->getForm();
746
747 50
        $this->parameterBag->set(OrderType::class, $form);
748
749 50
        return new Response();
750
    }
751
752
    /**
753
     * mode に応じて各変更ページへリダイレクトする.
754
     *
755
     * @ForwardOnly
756
     * @Route("/shopping/redirect_to_change", name="shopping_redirect_to_change")
757
     */
758 9
    public function redirectToChange(Request $request)
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
759
    {
760 9
        $form = $this->parameterBag->get(OrderType::class);
761
762
        // requestのバインド後、Calculatorに再集計させる
763
        //$app['eccube.service.calculate']($Order, $Order->getCustomer())->calculate();
764
765
        // 支払い方法の変更や配送業者の変更があった場合はDBに保持する.
766 9
        if ($form->isSubmitted() && $form->isValid()) {
767
            // POSTされたデータをDBに保持.
768 8
            $this->entityManager->flush();
769
770 8
            $mode = $form['mode']->getData();
771 8
            switch ($mode) {
772 7
                case 'shipping_change':
773
                    // お届け先設定一覧へリダイレクト
774 1
                    $param = $form['param']->getData();
775
776 1
                    return $this->redirectToRoute('shopping_shipping', ['id' => $param]);
777 7
                case 'shipping_edit_change':
778
                    // お届け先設定一覧へリダイレクト
779
                    $param = $form['param']->getData();
780
781
                    return $this->redirectToRoute('shopping_shipping_edit', ['id' => $param]);
782 7
                case 'shipping_multiple_change':
783
                    // 複数配送設定へリダイレクト
784
                    return $this->redirectToRoute('shopping_shipping_multiple');
785 7
                case 'payment':
786 7
                case 'delivery':
787
                default:
788 7
                    return $this->redirectToRoute('shopping');
789
            }
790
        }
791
792 1
        return new Response();
793
    }
794
795
    /**
796
     * 受注の存在チェック
797
     *
798
     * @ForwardOnly
799
     * @Route("/shopping/exists_order", name="shopping_exists_order")
800
     */
801 26
    public function existsOrder(Request $request)
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
802
    {
803 26
        $Order = $this->shoppingService->getOrder(OrderStatus::PROCESSING);
804 26
        if (!$Order) {
805
            log_info('購入処理中の受注情報がないため購入エラー');
806
            $this->addError('front.shopping.order.error');
807
808
            return $this->redirectToRoute('shopping_error');
809
        }
810 26
        $this->parameterBag->set('Order', $Order);
811
812 26
        return new Response();
813
    }
814
815
    /**
816
     * 受注完了処理
817
     *
818
     * @ForwardOnly
819
     * @Route("/shopping/complete_order", name="shopping_complete_order")
820
     */
821 6
    public function completeOrder(Request $request)
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
822
    {
823 6
        $form = $this->parameterBag->get(OrderType::class);
824
825 6
        if ($form->isSubmitted() && $form->isValid()) {
826
            /** @var Order $Order */
827 6
            $Order = $form->getData();
828 6
            log_info('購入処理開始', [$Order->getId()]);
829
830
            // トランザクション制御
831 6
            $em = $this->entityManager;
832 6
            $em->getConnection()->beginTransaction();
833
            try {
834
                // お問い合わせ、配送時間などのフォーム項目をセット
835
                // FormTypeで更新されるため不要
836
                //$app['eccube.service.shopping']->setFormData($Order, $data);
837
838 6
                $flowResult = $this->validatePurchaseFlow($Order);
839 6
                if ($flowResult->hasWarning() || $flowResult->hasError()) {
840
                    // TODO エラーメッセージ
841
                    throw new ShoppingException();
842
                }
843
844 6
                $paymentMethod = $this->createPaymentMethod($Order, $form);
845
846
                // 必要に応じて別のコントローラへ forward or redirect(移譲)
847 6
                $dispatcher = $paymentMethod->apply(); // 決済処理中.
848
                // 一旦、決済処理中になった後は、購入処理中に戻せない。キャンセル or 購入完了の仕様とする
849
                // ステータス履歴も保持しておく? 在庫引き当ての仕様もセットで。
850 6
                if ($dispatcher instanceof PaymentDispatcher) {
851
                    $response = $dispatcher->getResponse();
852
                    $this->entityManager->flush();
853
                    $this->entityManager->commit();
854
855
                    if ($response && ($response->isRedirection() || $response->getContent())) {
856
                        return $response;
857
                    }
858
859
                    if ($dispatcher->isForward()) {
860
                        return $this->forwardToRoute($dispatcher->getRoute(), $dispatcher->getPathParameters(), $dispatcher->getQueryParameters());
861
                    } else {
862
                        return $this->redirectToRoute($dispatcher->getRoute(), array_merge($dispatcher->getPathParameters(), $dispatcher->getQueryParameters()));
863
                    }
864
                }
865
866
                // 決済実行
867 6
                $response = $this->forwardToRoute('shopping_do_checkout_order');
868 6
                $this->entityManager->flush();
869 6
                $this->entityManager->commit();
870
871 6
                if ($response->isRedirection() || $response->getContent()) {
872
                    return $response;
873
                }
874
875 6
                log_info('購入処理完了', [$Order->getId()]);
876
            } catch (ShoppingException $e) {
877
                log_error('購入エラー', [$e->getMessage()]);
878
879
                $this->entityManager->getConnection()->rollback();
880
881
                $this->log($e);
0 ignored issues
show
Bug introduced by
The method log() does not seem to exist on object<Eccube\Controller\ShoppingController>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
882
                $this->addError($e->getMessage());
883
884
                return $this->redirectToRoute('shopping_error');
885
            } catch (\Exception $e) {
886
                log_error('予期しないエラー', [$e->getMessage()]);
887
888
                $this->entityManager->getConnection()->rollback();
889
890
                $this->addError('front.shopping.system.error');
891
892
                return $this->redirectToRoute('shopping_error');
893
            }
894
895 6
            return $this->forwardToRoute('shopping_after_complete');
896
        }
897
898
        return new Response();
899
    }
900
901
    /**
902
     * 決済完了処理
903
     *
904
     * @ForwardOnly
905
     * @Route("/shopping/do_checkout_order", name="shopping_do_checkout_order")
906
     */
907 6
    public function doCheckoutOrder(Request $request)
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
908
    {
909 6
        $form = $this->parameterBag->get(OrderType::class);
910 6
        $Order = $this->parameterBag->get('Order');
911
912 6
        $paymentMethod = $this->createPaymentMethod($Order, $form);
913
914
        // 決済実行
915 6
        $PaymentResult = $paymentMethod->checkout();
916 6
        $response = $PaymentResult->getResponse();
917 6
        if ($response && ($response->isRedirection() || $response->getContent())) {
918
            return $response;
919
        }
920
921 6
        if (!$PaymentResult->isSuccess()) {
922
            $this->entityManager->getConnection()->rollback();
923
924
            $this->addError($PaymentResult->getErrors());
925
        }
926
927 6
        return new Response();
928
    }
929
930
    /**
931
     * 受注完了の後処理
932
     *
933
     * @ForwardOnly
934
     * @Route("/shopping/after_complete", name="shopping_after_complete")
935
     */
936 6
    public function afterComplete(Request $request)
937
    {
938 6
        $form = $this->parameterBag->get(OrderType::class);
939 6
        $Order = $this->parameterBag->get('Order');
940
941
        // カート削除
942 6
        $this->cartService->clear();
943
944 6
        $event = new EventArgs(
945
            [
946 6
                'form' => $form,
947 6
                'Order' => $Order,
948
            ],
949 6
            $request
950
        );
951 6
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_SHOPPING_CONFIRM_PROCESSING, $event);
952
953 6 View Code Duplication
        if ($event->getResponse() !== null) {
954
            log_info('イベントレスポンス返却', [$Order->getId()]);
955
956
            return $event->getResponse();
957
        }
958
959
        // 受注IDをセッションにセット
960 6
        $this->session->set($this->sessionOrderKey, $Order->getId());
961
962
        // メール送信
963 6
        $MailHistory = $this->shoppingService->sendOrderMail($Order);
964
965 6
        $event = new EventArgs(
966
            [
967 6
                'form' => $form,
968 6
                'Order' => $Order,
969 6
                'MailHistory' => $MailHistory,
970
            ],
971 6
            $request
972
        );
973 6
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_SHOPPING_CONFIRM_COMPLETE, $event);
974
975 6 View Code Duplication
        if ($event->getResponse() !== null) {
976
            log_info('イベントレスポンス返却', [$Order->getId()]);
977
978
            return $event->getResponse();
979
        }
980
981
        // 完了画面表示
982 6
        return $this->redirectToRoute('shopping_complete');
983
    }
984
985 6
    private function createPaymentMethod(Order $Order, FormInterface $form)
986
    {
987 6
        $PaymentMethod = $this->container->get($Order->getPayment()->getMethodClass());
988 6
        $PaymentMethod->setOrder($Order);
989 6
        $PaymentMethod->setFormType($form);
990
991 6
        return $PaymentMethod;
992
    }
993
}
994