Completed
Push — sf/csv-headers ( 829ce9...de2c5f )
by Kiyotaka
06:12
created

ShoppingController   F

Complexity

Total Complexity 112

Size/Duplication

Total Lines 892
Duplicated Lines 0.9 %

Coupling/Cohesion

Components 1
Dependencies 27

Importance

Changes 0
Metric Value
dl 8
loc 892
rs 1.708
c 0
b 0
f 0
wmc 112
lcom 1
cbo 27

19 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 17 1
B index() 0 37 7
B redirectTo() 0 32 7
C confirm() 0 59 13
B order() 0 38 7
A complete() 0 37 3
C shipping() 0 67 10
D shippingEdit() 0 109 15
A login() 0 31 4
A shoppingError() 0 14 2
A checkToCart() 0 18 4
B initializeOrder() 0 47 5
A createShoppingForm() 0 21 1
B redirectToChange() 0 33 8
A existsOrder() 0 13 2
C completeOrder() 0 75 14
A doCheckoutOrder() 0 22 5
A afterComplete() 8 48 3
A createPaymentMethod() 0 8 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like ShoppingController often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ShoppingController, and based on these observations, apply Extract Interface, too.

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\BaseInfoRepository;
32
use Eccube\Repository\CustomerAddressRepository;
33
use Eccube\Repository\OrderRepository;
34
use Eccube\Service\CartService;
35
use Eccube\Service\OrderHelper;
36
use Eccube\Service\Payment\PaymentDispatcher;
37
use Eccube\Service\ShoppingService;
38
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
39
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
40
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
41
use Symfony\Component\Form\FormError;
42
use Symfony\Component\Form\FormInterface;
43
use Symfony\Component\HttpFoundation\ParameterBag;
44
use Symfony\Component\HttpFoundation\Request;
45
use Symfony\Component\HttpFoundation\Response;
46
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
47
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
48
49
class ShoppingController extends AbstractShoppingController
50
{
51
    /**
52
     * @var BaseInfo
53
     */
54
    protected $BaseInfo;
55
56
    /**
57
     * @var OrderHelper
58
     */
59
    protected $orderHelper;
60
61
    /**
62
     * @var CartService
63
     */
64
    protected $cartService;
65
66
    /**
67
     * @var ShoppingService
68
     */
69
    protected $shoppingService;
70
71
    /**
72
     * @var CustomerAddressRepository
73
     */
74
    protected $customerAddressRepository;
75
76
    /**
77
     * @var ParameterBag
78
     */
79
    protected $parameterBag;
80
81
    /**
82
     * ShoppingController constructor.
83
     *
84
     * @param BaseInfoRepository $baseInfoRepository
85
     * @param OrderHelper $orderHelper
86
     * @param CartService $cartService
87
     * @param ShoppingService $shoppingService
88
     * @param CustomerAddressRepository $customerAddressRepository
89
     * @param ParameterBag $parameterBag
90
     */
91
    public function __construct(
92
        BaseInfoRepository $baseInfoRepository,
93
        OrderHelper $orderHelper,
94
        CartService $cartService,
95
        ShoppingService $shoppingService,
96
        CustomerAddressRepository $customerAddressRepository,
97
        OrderRepository $orderRepository,
98
        ParameterBag $parameterBag
99
    ) {
100
        $this->BaseInfo = $baseInfoRepository->get();
101
        $this->orderHelper = $orderHelper;
102
        $this->cartService = $cartService;
103
        $this->shoppingService = $shoppingService;
104
        $this->customerAddressRepository = $customerAddressRepository;
105
        $this->orderRepository = $orderRepository;
0 ignored issues
show
Bug introduced by
The property orderRepository does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
106
        $this->parameterBag = $parameterBag;
107
    }
108
109
    /**
110
     * 購入画面表示
111
     *
112
     * @Route("/shopping", name="shopping")
113
     * @Template("Shopping/index.twig")
114
     */
115
    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...
116
    {
117
        // カートチェック
118
        $response = $this->forwardToRoute('shopping_check_to_cart');
119
        if ($response->isRedirection() || $response->getContent()) {
120
            return $response;
121
        }
122
123
        // 受注情報を初期化
124
        $response = $this->forwardToRoute('shopping_initialize_order');
125
        if ($response->isRedirection() || $response->getContent()) {
126
            return $response;
127
        }
128
129
        /** @var Order $Order */
130
        $Order = $this->parameterBag->get('Order');
131
132
        // 単価集計
133
        $flowResult = $this->validatePurchaseFlow($Order);
134
135
        // 明細が丸められる場合に, カートから注文画面へ遷移できなくなるため, 集計の結果を保存する
136
        $this->entityManager->flush();
137
138
        // フォームを生成する
139
        $this->forwardToRoute('shopping_create_form');
140
141
        if ($flowResult->hasWarning() || $flowResult->hasError()) {
142
            return $this->redirectToRoute('cart');
143
        }
144
145
        $form = $this->parameterBag->get(OrderType::class);
146
147
        return [
148
            'form' => $form->createView(),
149
            'Order' => $Order,
150
        ];
151
    }
152
153
    /**
154
     * 購入確認画面から, 他の画面へのリダイレクト.
155
     * 配送業者や支払方法、お問い合わせ情報をDBに保持してから遷移する.
156
     *
157
     * @Route("/shopping/redirect", name="shopping_redirect_to")
158
     * @Template("Shopping/index.twig")
159
     */
160
    public function redirectTo(Request $request)
161
    {
162
        // カートチェック
163
        $response = $this->forwardToRoute('shopping_check_to_cart');
164
        if ($response->isRedirection() || $response->getContent()) {
165
            return $response;
166
        }
167
168
        // 受注の存在チェック
169
        $response = $this->forwardToRoute('shopping_exists_order');
170
        if ($response->isRedirection() || $response->getContent()) {
171
            return $response;
172
        }
173
174
        // フォームの生成
175
        $this->forwardToRoute('shopping_create_form');
176
        $form = $this->parameterBag->get(OrderType::class);
177
        $form->handleRequest($request);
178
179
        // 各種変更ページへリダイレクトする
180
        $response = $this->forwardToRoute('shopping_redirect_to_change');
181
        if ($response->isRedirection() || $response->getContent()) {
182
            return $response;
183
        }
184
        $form = $this->parameterBag->get(OrderType::class);
185
        $Order = $this->parameterBag->get('Order');
186
187
        return [
188
            'form' => $form->createView(),
189
            'Order' => $Order,
190
        ];
191
    }
192
193
    /**
194
     * 購入処理
195
     *
196
     * @Route("/shopping/confirm", name="shopping_confirm")
197
     * @Method("POST")
198
     * @Template("Shopping/confirm.twig")
199
     */
200
    public function confirm(Request $request)
201
    {
202
        // カートチェック
203
        $response = $this->forwardToRoute('shopping_check_to_cart');
204
        if ($response->isRedirection() || $response->getContent()) {
205
            return $response;
206
        }
207
208
        // 受注の存在チェック
209
        $response = $this->forwardToRoute('shopping_exists_order');
210
        if ($response->isRedirection() || $response->getContent()) {
211
            return $response;
212
        }
213
214
        // フォームの生成
215
        $this->forwardToRoute('shopping_create_form');
216
        $form = $this->parameterBag->get(OrderType::class);
217
        $form->handleRequest($request);
218
219
        $form = $this->parameterBag->get(OrderType::class);
220
        $Order = $this->parameterBag->get('Order');
221
222
        // フォームエラーチェック
223
        if (!$form->isValid()) {
224
            $response = $this->forwardToRoute('shopping_redirect_to');
225
226
            return $response;
227
        }
228
229
        $flowResult = $this->validatePurchaseFlow($Order);
230
        if ($flowResult->hasWarning() || $flowResult->hasError()) {
231
            return $this->redirectToRoute('shopping_error');
232
        }
233
234
        $paymentMethod = $this->createPaymentMethod($Order, $form);
235
236
        $PaymentResult = $paymentMethod->verify();
237
        // エラーの場合は注文入力画面に戻す?
238
        if ($PaymentResult instanceof PaymentResult) {
0 ignored issues
show
Bug introduced by
The class Eccube\Controller\PaymentResult does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
239
            if (!$PaymentResult->isSuccess()) {
240
                $this->entityManager->getConnection()->rollback();
241
242
                $this->addError($PaymentResult->getErrors());
243
            }
244
245
            $response = $PaymentResult->getResponse();
246
            if ($response && ($response->isRedirection() || $response->getContent())) {
247
                $this->entityManager->flush();
248
249
                return $response;
250
            }
251
        }
252
        $this->entityManager->flush();
253
254
        return [
255
            'form' => $form->createView(),
256
            'Order' => $Order,
257
        ];
258
    }
259
260
    /**
261
     * 購入処理
262
     *
263
     * @Route("/shopping/order", name="shopping_order")
264
     * @Method("POST")
265
     * @Template("Shopping/index.twig")
266
     */
267
    public function order(Request $request)
268
    {
269
        // カートチェック
270
        $response = $this->forwardToRoute('shopping_check_to_cart');
271
        if ($response->isRedirection() || $response->getContent()) {
272
            return $response;
273
        }
274
275
        // 受注の存在チェック
276
        $response = $this->forwardToRoute('shopping_exists_order');
277
        if ($response->isRedirection() || $response->getContent()) {
278
            return $response;
279
        }
280
281
        // form作成
282
        // FIXME イベントハンドラを外から渡したい
283
        $this->forwardToRoute('shopping_create_form');
284
285
        $form = $this->parameterBag->get(OrderType::class);
286
        $Order = $this->parameterBag->get('Order');
287
        $usePoint = $Order->getUsePoint();
288
289
        $form->handleRequest($request);
290
        $Order->setUsePoint($usePoint);
291
292
        // 受注処理
293
        $response = $this->forwardToRoute('shopping_complete_order');
294
        if ($response->isRedirection() || $response->getContent()) {
295
            return $response;
296
        }
297
298
        log_info('購入チェックエラー', [$Order->getId()]);
299
300
        return [
301
            'form' => $form->createView(),
302
            'Order' => $Order,
303
        ];
304
    }
305
306
    /**
307
     * 購入完了画面表示
308
     *
309
     * @Route("/shopping/complete", name="shopping_complete")
310
     * @Template("Shopping/complete.twig")
311
     */
312
    public function complete(Request $request)
313
    {
314
        // 受注IDを取得
315
        $orderId = $this->session->get($this->sessionOrderKey);
316
317
        if (empty($orderId)) {
318
            return $this->redirectToRoute('homepage');
319
        }
320
321
        $Order = $this->orderRepository->find($orderId);
322
323
        $event = new EventArgs(
324
            [
325
                'Order' => $Order,
326
            ],
327
            $request
328
        );
329
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_SHOPPING_COMPLETE_INITIALIZE, $event);
330
331
        if ($event->getResponse() !== null) {
332
            return $event->getResponse();
333
        }
334
335
        // 受注に関連するセッションを削除
336
        $this->session->remove($this->sessionOrderKey);
337
        $this->session->remove($this->sessionKey);
338
        $this->session->remove($this->sessionCustomerAddressKey);
339
340
        log_info('購入処理完了', [$Order->getId()]);
341
342
        $hasNextCart = !empty($this->cartService->getCarts());
343
344
        return [
345
            'Order' => $Order,
346
            'hasNextCart' => $hasNextCart,
347
        ];
348
    }
349
350
    /**
351
     * お届け先の設定一覧からの選択
352
     *
353
     * @Route("/shopping/shipping/{id}", name="shopping_shipping", requirements={"id" = "\d+"})
354
     * @Template("Shopping/shipping.twig")
355
     */
356
    public function shipping(Request $request, Shipping $Shipping)
357
    {
358
        // カートチェック
359
        $response = $this->forwardToRoute('shopping_check_to_cart');
360
        if ($response->isRedirection() || $response->getContent()) {
361
            return $response;
362
        }
363
364
        // 受注の存在チェック
365
        $response = $this->forwardToRoute('shopping_exists_order');
366
        if ($response->isRedirection() || $response->getContent()) {
367
            return $response;
368
        }
369
370
        // 受注に紐づくShippingかどうかのチェック.
371
        /** @var Order $Order */
372
        $Order = $this->parameterBag->get('Order');
373
        if (!$Order->findShipping($Shipping->getId())) {
374
            throw new NotFoundHttpException();
375
        }
376
377
        $builder = $this->formFactory->createBuilder(CustomerAddressType::class, null, [
378
            'customer' => $this->getUser(),
379
            'shipping' => $Shipping,
380
        ]);
381
382
        $form = $builder->getForm();
383
        $form->handleRequest($request);
384
385
        if ($form->isSubmitted() && $form->isValid()) {
386
            log_info('お届先情報更新開始', [$Shipping->getId()]);
387
388
            /** @var CustomerAddress $CustomerAddress */
389
            $CustomerAddress = $form['addresses']->getData();
390
391
            // お届け先情報を更新
392
            $Shipping->setFromCustomerAddress($CustomerAddress);
393
394
            // 合計金額の再計算
395
            $flowResult = $this->validatePurchaseFlow($Order);
396
            if ($flowResult->hasWarning() || $flowResult->hasError()) {
397
                return $this->redirectToRoute('shopping_error');
398
            }
399
400
            // 配送先を更新
401
            $this->entityManager->flush();
402
403
            $event = new EventArgs(
404
                [
405
                    'Order' => $Order,
406
                    'Shipping' => $Shipping,
407
                ],
408
                $request
409
            );
410
            $this->eventDispatcher->dispatch(EccubeEvents::FRONT_SHOPPING_SHIPPING_COMPLETE, $event);
411
412
            log_info('お届先情報更新完了', [$Shipping->getId()]);
413
414
            return $this->redirectToRoute('shopping');
415
        }
416
417
        return [
418
            'form' => $form->createView(),
419
            'Customer' => $this->getUser(),
420
            'shippingId' => $Shipping->getId(),
421
        ];
422
    }
423
424
    /**
425
     * お届け先の設定(非会員でも使用する)
426
     *
427
     * @Route("/shopping/shipping_edit/{id}", name="shopping_shipping_edit", requirements={"id" = "\d+"})
428
     * @Template("Shopping/shipping_edit.twig")
429
     */
430
    public function shippingEdit(Request $request, $id)
431
    {
432
        // 配送先住所最大値判定
433
        $Customer = $this->getUser();
434
        if ($this->isGranted('IS_AUTHENTICATED_FULLY')) {
435
            $addressCurrNum = count($this->getUser()->getCustomerAddresses());
436
            $addressMax = $this->eccubeConfig['eccube_deliv_addr_max'];
437
            if ($addressCurrNum >= $addressMax) {
438
                throw new NotFoundHttpException(trans('shoppingcontroller.text.error.number_of_address'));
439
            }
440
        }
441
442
        // カートチェック
443
        $response = $this->forwardToRoute('shopping_check_to_cart');
444
        if ($response->isRedirection() || $response->getContent()) {
445
            return $response;
446
        }
447
448
        // 受注の存在チェック
449
        $response = $this->forwardToRoute('shopping_exists_order');
450
        if ($response->isRedirection() || $response->getContent()) {
451
            return $response;
452
        }
453
454
        /** @var Order $Order */
455
        $Order = $this->parameterBag->get('Order');
456
457
        $Shipping = $Order->findShipping($id);
458
        if (!$Shipping) {
459
            throw new NotFoundHttpException(trans('shoppingcontroller.text.error.set_address'));
460
        }
461
        if ($this->isGranted('IS_AUTHENTICATED_FULLY')) {
462
            $Shipping->clearCustomerAddress();
463
        }
464
465
        $CustomerAddress = new CustomerAddress();
466
        if ($this->isGranted('IS_AUTHENTICATED_FULLY')) {
467
            $CustomerAddress->setCustomer($Customer);
0 ignored issues
show
Bug introduced by
It seems like $Customer defined by $this->getUser() on line 433 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...
468
        } else {
469
            $CustomerAddress->setFromShipping($Shipping);
470
        }
471
472
        $builder = $this->formFactory->createBuilder(ShoppingShippingType::class, $CustomerAddress);
473
474
        $event = new EventArgs(
475
            [
476
                'builder' => $builder,
477
                'Order' => $Order,
478
                'Shipping' => $Shipping,
479
                'CustomerAddress' => $CustomerAddress,
480
            ],
481
            $request
482
        );
483
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_SHOPPING_SHIPPING_EDIT_INITIALIZE, $event);
484
485
        $form = $builder->getForm();
486
487
        $form->handleRequest($request);
488
489
        if ($form->isSubmitted() && $form->isValid()) {
490
            log_info('お届け先追加処理開始', ['id' => $Order->getId(), 'shipping' => $id]);
491
492
            // 会員の場合、お届け先情報を新規登録
493
            $Shipping->setFromCustomerAddress($CustomerAddress);
494
495
            if ($Customer instanceof Customer) {
496
                $this->entityManager->persist($CustomerAddress);
497
                log_info(
498
                    '新規お届け先登録',
499
                    [
500
                        'id' => $Order->getId(),
501
                        'shipping' => $id,
502
                        'customer address' => $CustomerAddress->getId(),
503
                    ]
504
                );
505
            }
506
507
            // 配送料金の設定
508
            $this->shoppingService->setShippingDeliveryFee($Shipping);
509
510
            // 合計金額の再計算
511
            $flowResult = $this->validatePurchaseFlow($Order);
512
            if ($flowResult->hasWarning() || $flowResult->hasError()) {
513
                return $this->redirectToRoute('shopping_error');
514
            }
515
516
            // 配送先を更新
517
            $this->entityManager->flush();
518
519
            $event = new EventArgs(
520
                [
521
                    'form' => $form,
522
                    'Shipping' => $Shipping,
523
                    'CustomerAddress' => $CustomerAddress,
524
                ],
525
                $request
526
            );
527
            $this->eventDispatcher->dispatch(EccubeEvents::FRONT_SHOPPING_SHIPPING_EDIT_COMPLETE, $event);
528
529
            log_info('お届け先追加処理完了', ['id' => $Order->getId(), 'shipping' => $id]);
530
531
            return $this->redirectToRoute('shopping');
532
        }
533
534
        return [
535
            'form' => $form->createView(),
536
            'shippingId' => $id,
537
        ];
538
    }
539
540
    /**
541
     * ログイン
542
     *
543
     * @Route("/shopping/login", name="shopping_login")
544
     * @Template("Shopping/login.twig")
545
     */
546
    public function login(Request $request, AuthenticationUtils $authenticationUtils)
547
    {
548
        if ($this->isGranted('IS_AUTHENTICATED_FULLY')) {
549
            return $this->redirectToRoute('shopping');
550
        }
551
552
        /* @var $form \Symfony\Component\Form\FormInterface */
553
        $builder = $this->formFactory->createNamedBuilder('', CustomerLoginType::class);
554
555
        if ($this->isGranted('IS_AUTHENTICATED_REMEMBERED')) {
556
            $Customer = $this->getUser();
557
            if ($Customer) {
558
                $builder->get('login_email')->setData($Customer->getEmail());
559
            }
560
        }
561
562
        $event = new EventArgs(
563
            [
564
                'builder' => $builder,
565
            ],
566
            $request
567
        );
568
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_SHOPPING_LOGIN_INITIALIZE, $event);
569
570
        $form = $builder->getForm();
571
572
        return [
573
            'error' => $authenticationUtils->getLastAuthenticationError(),
574
            'form' => $form->createView(),
575
        ];
576
    }
577
578
    /**
579
     * 購入エラー画面表示
580
     *
581
     * @Route("/shopping/error", name="shopping_error")
582
     * @Template("Shopping/shopping_error.twig")
583
     */
584
    public function shoppingError(Request $request)
585
    {
586
        $event = new EventArgs(
587
            [],
588
            $request
589
        );
590
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_SHOPPING_SHIPPING_ERROR_COMPLETE, $event);
591
592
        if ($event->getResponse() !== null) {
593
            return $event->getResponse();
594
        }
595
596
        return [];
597
    }
598
599
    /**
600
     * カート画面のチェック
601
     *
602
     * @ForwardOnly
603
     * @Route("/shopping/check_to_cart", name="shopping_check_to_cart")
604
     */
605
    public function checkToCart(Request $request)
606
    {
607
        $Cart = $this->cartService->getCart();
608
        if ($Cart && count($Cart->getCartItems()) > 0) {
609
            $divide = $request->getSession()->get('cart.divide');
610
            if ($divide) {
611
                log_info('種別が異なる商品がカートと結合されたためカート画面にリダイレクト');
612
613
                return $this->redirectToRoute('cart');
614
            }
615
616
            return new Response();
617
        }
618
        log_info('カートに商品が入っていないためショッピングカート画面にリダイレクト');
619
620
        // カートが存在しない時はエラー
621
        return $this->redirectToRoute('cart');
622
    }
623
624
    /**
625
     * 受注情報を初期化する.
626
     *
627
     * @ForwardOnly
628
     * @Route("/shopping/initialize_order", name="shopping_initialize_order")
629
     */
630
    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...
631
    {
632
        // 購入処理中の受注情報を取得
633
        $Order = $this->shoppingService->getOrder(OrderStatus::PROCESSING);
634
635
        // 初回アクセス(受注情報がない)の場合は, 受注情報を作成
636
        if (is_null($Order)) {
637
            // 未ログインの場合, ログイン画面へリダイレクト.
638
            if (!$this->isGranted('IS_AUTHENTICATED_FULLY')) {
639
                // 非会員でも一度会員登録されていればショッピング画面へ遷移
640
                $Customer = $this->shoppingService->getNonMember($this->sessionKey);
641
642
                if (is_null($Customer)) {
643
                    log_info('未ログインのためログイン画面にリダイレクト');
644
645
                    return $this->redirectToRoute('shopping_login');
646
                }
647
            } else {
648
                $Customer = $this->getUser();
649
            }
650
651
            try {
652
                // 受注情報を作成
653
                $Order = $this->orderHelper->createProcessingOrder(
654
                    $Customer,
655
                    $this->cartService->getCart()->getCartItems()
656
                );
657
                $this->cartService->setPreOrderId($Order->getPreOrderId());
658
                $this->cartService->save();
659
            } catch (CartException $e) {
660
                log_error('初回受注情報作成エラー', [$e->getMessage()]);
661
                $this->addRequestError($e->getMessage());
662
663
                return $this->redirectToRoute('cart');
664
            }
665
666
            // セッション情報を削除
667
            $this->session->remove($this->sessionOrderKey);
668
        }
669
670
        // 受注関連情報を最新状態に更新
671
        $this->entityManager->refresh($Order);
672
673
        $this->parameterBag->set('Order', $Order);
674
675
        return new Response();
676
    }
677
678
    /**
679
     * フォームを作成し, イベントハンドラを設定する
680
     *
681
     * @ForwardOnly
682
     * @Route("/shopping/create_form", name="shopping_create_form")
683
     */
684
    public function createShoppingForm(Request $request)
685
    {
686
        $Order = $this->parameterBag->get('Order');
687
        // フォームの生成
688
        $builder = $this->formFactory->createBuilder(OrderType::class, $Order);
689
690
        $event = new EventArgs(
691
                [
692
                    'builder' => $builder,
693
                    'Order' => $Order,
694
                ],
695
                $request
696
            );
697
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_SHOPPING_INDEX_INITIALIZE, $event);
698
699
        $form = $builder->getForm();
700
701
        $this->parameterBag->set(OrderType::class, $form);
702
703
        return new Response();
704
    }
705
706
    /**
707
     * mode に応じて各変更ページへリダイレクトする.
708
     *
709
     * @ForwardOnly
710
     * @Route("/shopping/redirect_to_change", name="shopping_redirect_to_change")
711
     */
712
    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...
713
    {
714
        $form = $this->parameterBag->get(OrderType::class);
715
716
        // 支払い方法の変更や配送業者の変更があった場合はDBに保持する.
717
        if ($form->isSubmitted() && $form->isValid()) {
718
            // POSTされたデータをDBに保持.
719
            $this->entityManager->flush();
720
721
            $mode = $form['mode']->getData();
722
            switch ($mode) {
723
                case 'shipping_change':
724
                    // お届け先設定一覧へリダイレクト
725
                    $param = $form['param']->getData();
726
727
                    return $this->redirectToRoute('shopping_shipping', ['id' => $param]);
728
                case 'shipping_edit_change':
729
                    // お届け先設定一覧へリダイレクト
730
                    $param = $form['param']->getData();
731
732
                    return $this->redirectToRoute('shopping_shipping_edit', ['id' => $param]);
733
                case 'shipping_multiple_change':
734
                    // 複数配送設定へリダイレクト
735
                    return $this->redirectToRoute('shopping_shipping_multiple');
736
                case 'payment':
737
                case 'delivery':
738
                default:
739
                    return $this->redirectToRoute('shopping');
740
            }
741
        }
742
743
        return new Response();
744
    }
745
746
    /**
747
     * 受注の存在チェック
748
     *
749
     * @ForwardOnly
750
     * @Route("/shopping/exists_order", name="shopping_exists_order")
751
     */
752
    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...
753
    {
754
        $Order = $this->shoppingService->getOrder(OrderStatus::PROCESSING);
755
        if (!$Order) {
756
            log_info('購入処理中の受注情報がないため購入エラー');
757
            $this->addError('front.shopping.order.error');
758
759
            return $this->redirectToRoute('shopping_error');
760
        }
761
        $this->parameterBag->set('Order', $Order);
762
763
        return new Response();
764
    }
765
766
    /**
767
     * 受注完了処理
768
     *
769
     * @ForwardOnly
770
     * @Route("/shopping/complete_order", name="shopping_complete_order")
771
     */
772
    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...
773
    {
774
        $form = $this->parameterBag->get(OrderType::class);
775
776
        if ($form->isSubmitted() && $form->isValid()) {
777
            /** @var Order $Order */
778
            $Order = $form->getData();
779
            log_info('購入処理開始', [$Order->getId()]);
780
781
            // トランザクション制御
782
            $em = $this->entityManager;
783
            $em->getConnection()->beginTransaction();
784
            try {
785
                $flowResult = $this->validatePurchaseFlow($Order);
786
                if ($flowResult->hasWarning() || $flowResult->hasError()) {
787
                    // TODO エラーメッセージ
788
                    throw new ShoppingException();
789
                }
790
791
                $paymentMethod = $this->createPaymentMethod($Order, $form);
792
793
                // 必要に応じて別のコントローラへ forward or redirect(移譲)
794
                $dispatcher = $paymentMethod->apply(); // 決済処理中.
795
                // 一旦、決済処理中になった後は、購入処理中に戻せない。キャンセル or 購入完了の仕様とする
796
                // ステータス履歴も保持しておく? 在庫引き当ての仕様もセットで。
797
                if ($dispatcher instanceof PaymentDispatcher) {
798
                    $response = $dispatcher->getResponse();
799
                    $this->entityManager->flush();
800
                    $this->entityManager->commit();
801
802
                    if ($response && ($response->isRedirection() || $response->getContent())) {
803
                        return $response;
804
                    }
805
806
                    if ($dispatcher->isForward()) {
807
                        return $this->forwardToRoute($dispatcher->getRoute(), $dispatcher->getPathParameters(), $dispatcher->getQueryParameters());
808
                    } else {
809
                        return $this->redirectToRoute($dispatcher->getRoute(), array_merge($dispatcher->getPathParameters(), $dispatcher->getQueryParameters()));
810
                    }
811
                }
812
813
                // 決済実行
814
                $response = $this->forwardToRoute('shopping_do_checkout_order');
815
                $this->entityManager->flush();
816
                $this->entityManager->commit();
817
818
                if ($response->isRedirection() || $response->getContent()) {
819
                    return $response;
820
                }
821
822
                log_info('購入処理完了', [$Order->getId()]);
823
            } catch (ShoppingException $e) {
824
                log_error('購入エラー', [$e->getMessage()]);
825
826
                $this->entityManager->getConnection()->rollback();
827
828
                $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...
829
                $this->addError($e->getMessage());
830
831
                return $this->redirectToRoute('shopping_error');
832
            } catch (\Exception $e) {
833
                log_error('予期しないエラー', [$e->getMessage()]);
834
835
                $this->entityManager->getConnection()->rollback();
836
837
                $this->addError('front.shopping.system.error');
838
839
                return $this->redirectToRoute('shopping_error');
840
            }
841
842
            return $this->forwardToRoute('shopping_after_complete');
843
        }
844
845
        return new Response();
846
    }
847
848
    /**
849
     * 決済完了処理
850
     *
851
     * @ForwardOnly
852
     * @Route("/shopping/do_checkout_order", name="shopping_do_checkout_order")
853
     */
854
    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...
855
    {
856
        $form = $this->parameterBag->get(OrderType::class);
857
        $Order = $this->parameterBag->get('Order');
858
859
        $paymentMethod = $this->createPaymentMethod($Order, $form);
860
861
        // 決済実行
862
        $PaymentResult = $paymentMethod->checkout();
863
        $response = $PaymentResult->getResponse();
864
        if ($response && ($response->isRedirection() || $response->getContent())) {
865
            return $response;
866
        }
867
868
        if (!$PaymentResult->isSuccess()) {
869
            $this->entityManager->getConnection()->rollback();
870
871
            $this->addError($PaymentResult->getErrors());
872
        }
873
874
        return new Response();
875
    }
876
877
    /**
878
     * 受注完了の後処理
879
     *
880
     * @ForwardOnly
881
     * @Route("/shopping/after_complete", name="shopping_after_complete")
882
     */
883
    public function afterComplete(Request $request)
884
    {
885
        $form = $this->parameterBag->get(OrderType::class);
886
        $Order = $this->parameterBag->get('Order');
887
888
        // カート削除
889
        $this->cartService->clear();
890
891
        $event = new EventArgs(
892
            [
893
                'form' => $form,
894
                'Order' => $Order,
895
            ],
896
            $request
897
        );
898
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_SHOPPING_CONFIRM_PROCESSING, $event);
899
900 View Code Duplication
        if ($event->getResponse() !== null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
901
            log_info('イベントレスポンス返却', [$Order->getId()]);
902
903
            return $event->getResponse();
904
        }
905
906
        // 受注IDをセッションにセット
907
        $this->session->set($this->sessionOrderKey, $Order->getId());
908
909
        // メール送信
910
        $MailHistory = $this->shoppingService->sendOrderMail($Order);
911
912
        $event = new EventArgs(
913
            [
914
                'form' => $form,
915
                'Order' => $Order,
916
                'MailHistory' => $MailHistory,
917
            ],
918
            $request
919
        );
920
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_SHOPPING_CONFIRM_COMPLETE, $event);
921
922 View Code Duplication
        if ($event->getResponse() !== null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
923
            log_info('イベントレスポンス返却', [$Order->getId()]);
924
925
            return $event->getResponse();
926
        }
927
928
        // 完了画面表示
929
        return $this->redirectToRoute('shopping_complete');
930
    }
931
932
    private function createPaymentMethod(Order $Order, FormInterface $form)
933
    {
934
        $PaymentMethod = $this->container->get($Order->getPayment()->getMethodClass());
935
        $PaymentMethod->setOrder($Order);
936
        $PaymentMethod->setFormType($form);
937
938
        return $PaymentMethod;
939
    }
940
}
941