Failed Conditions
Pull Request — 4.0 (#3650)
by chihiro
12:55 queued 06:00
created

ShoppingController::error()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
nc 4
nop 2
dl 0
loc 21
ccs 5
cts 5
cp 1
crap 3
rs 9.584
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\Controller;
15
16
use Eccube\Entity\CustomerAddress;
17
use Eccube\Entity\Order;
18
use Eccube\Entity\Shipping;
19
use Eccube\Event\EccubeEvents;
20
use Eccube\Event\EventArgs;
21
use Eccube\Exception\ShoppingException;
22
use Eccube\Form\Type\Front\CustomerLoginType;
23
use Eccube\Form\Type\Front\ShoppingShippingType;
24
use Eccube\Form\Type\Shopping\CustomerAddressType;
25
use Eccube\Form\Type\Shopping\OrderType;
26
use Eccube\Repository\OrderRepository;
27
use Eccube\Service\CartService;
28
use Eccube\Service\MailService;
29
use Eccube\Service\OrderHelper;
30
use Eccube\Service\Payment\PaymentDispatcher;
31
use Eccube\Service\Payment\PaymentMethodInterface;
32
use Eccube\Service\PurchaseFlow\PurchaseContext;
33
use Eccube\Service\PurchaseFlow\PurchaseFlow;
34
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
35
use Symfony\Component\Form\FormInterface;
36
use Symfony\Component\HttpFoundation\Request;
37
use Symfony\Component\Routing\Annotation\Route;
38
use Symfony\Component\Routing\RouterInterface;
39
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
40
41
class ShoppingController extends AbstractShoppingController
42
{
43
    /**
44
     * @var CartService
45
     */
46
    protected $cartService;
47
48
    /**
49
     * @var MailService
50
     */
51
    protected $mailService;
52
53
    /**
54
     * @var OrderHelper
55
     */
56
    protected $orderHelper;
57
58
    /**
59
     * @var OrderRepository
60
     */
61
    protected $orderRepository;
62
63
    public function __construct(
64
        CartService $cartService,
65
        MailService $mailService,
66
        OrderRepository $orderRepository,
67
        OrderHelper $orderHelper
68
    ) {
69
        $this->cartService = $cartService;
70
        $this->mailService = $mailService;
71
        $this->orderRepository = $orderRepository;
72
        $this->orderHelper = $orderHelper;
73
    }
74
75
    /**
76
     * 注文手続き画面を表示する
77
     *
78
     * 未ログインまたはRememberMeログインの場合はログイン画面に遷移させる.
79
     * ただし、非会員でお客様情報を入力済の場合は遷移させない.
80
     *
81
     * カート情報から受注データを生成し, `pre_order_id`でカートと受注の紐付けを行う.
82
     * 既に受注が生成されている場合(pre_order_idで取得できる場合)は, 受注の生成を行わずに画面を表示する.
83
     *
84
     * purchaseFlowの集計処理実行後, warning/errorがあればカートに戻す.
85
     *
86
     * @Route("/shopping", name="shopping")
87
     * @Template("Shopping/index.twig")
88
     */
89
    public function index()
90
    {
91 59
        // ログイン状態のチェック.
92
        if ($this->orderHelper->isLoginRequired()) {
93
            log_info('[注文手続] 未ログインもしくはRememberMeログインのため, ログイン画面に遷移します.');
94
95
            return $this->redirectToRoute('shopping_login');
96
        }
97
98
        // カートチェック.
99
        $Cart = $this->cartService->getCart();
100 59
        if (!$this->orderHelper->verifyCart($Cart)) {
0 ignored issues
show
Security Bug introduced by
It seems like $Cart defined by $this->cartService->getCart() on line 99 can also be of type false; however, Eccube\Service\OrderHelper::verifyCart() does only seem to accept null|object<Eccube\Entity\Cart>, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
101 59
            log_info('[注文手続] カートが購入フローへ遷移できない状態のため, カート画面に遷移します.');
102 59
103 59
            return $this->redirectToRoute('cart');
104 59
        }
105 59
106 59
        // 受注の初期化.
107
        log_info('[注文手続] 受注の初期化処理を開始します.');
108
        $Customer = $this->getUser() ? $this->getUser() : $this->orderHelper->getNonMember();
109
        $Order = $this->orderHelper->initializeOrder($Cart, $Customer);
0 ignored issues
show
Bug introduced by
It seems like $Cart defined by $this->cartService->getCart() on line 99 can also be of type false or null; however, Eccube\Service\OrderHelper::initializeOrder() does only seem to accept object<Eccube\Entity\Cart>, 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...
110
111
        // 集計処理.
112
        log_info('[注文手続] 集計処理を開始します.', [$Order->getId()]);
113
        $flowResult = $this->validatePurchaseFlow($Order);
114
        $this->entityManager->flush();
115 51
116 View Code Duplication
        if ($flowResult->hasWarning() || $flowResult->hasError()) {
117
            log_info('[注文手続] WarningもしくはErrorが発生したためカート画面へ遷移します.',
118 51
                [$flowResult->getWarning(), $flowResult->getErrors()]);
119 51
120 1
            return $this->redirectToRoute('cart');
121
        }
122
123
        $form = $this->createForm(OrderType::class, $Order);
124 50
125 50
        return [
126
            'form' => $form->createView(),
127
            'Order' => $Order,
128
        ];
129
    }
130 50
131
    /**
132
     * 他画面への遷移を行う.
133 50
     *
134
     * お届け先編集画面など, 他画面へ遷移する際に, フォームの値をDBに保存してからリダイレクトさせる.
135
     * フォームの`redirect_to`パラメータの値にリダイレクトを行う.
136 50
     * `redirect_to`パラメータはpath('遷移先のルーティング')が渡される必要がある.
137
     *
138
     * 外部のURLやPathを渡された場合($router->matchで展開出来ない場合)は, 購入エラーとする.
139 50
     *
140
     * プラグインやカスタマイズでこの機能を使う場合は, twig側で以下のように記述してください.
141 50
     *
142 10
     * <button class="redirect-onclick" data-path="path('ルーティング')">更新する</button>
143
     *
144
     * redirect-*は, 以下を使用できます.
145 45
     *
146
     * - redirect-onclick
147
     * - redirect-onchange
148 45
     * - redirect-onblur
149 45
     *
150
     * data-pathは任意のパラメータです. デフォルトでは注文手続き画面へリダイレクトします.
151
     *
152
     * @Route("/shopping/redirect_to", name="shopping_redirect_to", methods={"POST"})
153
     * @Template("Shopping/index.twig")
154
     */
155
    public function redirectTo(Request $request, RouterInterface $router)
156
    {
157
        // ログイン状態のチェック.
158
        if ($this->orderHelper->isLoginRequired()) {
159
            log_info('[リダイレクト] 未ログインもしくはRememberMeログインのため, ログイン画面に遷移します.');
160 20
161
            return $this->redirectToRoute('shopping_login');
162
        }
163 20
164 20
        // 受注の存在チェック.
165
        $preOrderId = $this->cartService->getPreOrderId();
166
        $Order = $this->orderHelper->getPurchaseProcessingOrder($preOrderId);
0 ignored issues
show
Bug introduced by
It seems like $preOrderId defined by $this->cartService->getPreOrderId() on line 165 can also be of type string; however, Eccube\Service\OrderHelp...rchaseProcessingOrder() does only seem to accept null, 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...
167
        if (!$Order) {
168
            log_info('[リダイレクト] 購入処理中の受注が存在しません.');
169 20
170 20
            return $this->redirectToRoute('shopping_error');
171
        }
172
173
        $form = $this->createForm(OrderType::class, $Order);
174
        $form->handleRequest($request);
175 20
176 20
        if ($form->isSubmitted() && $form->isValid()) {
177 20
            log_info('[リダイレクト] 集計処理を開始します.', [$Order->getId()]);
178
            $flowResult = $this->validatePurchaseFlow($Order);
179
            $this->entityManager->flush();
180 20
181 20 View Code Duplication
            if ($flowResult->hasWarning() || $flowResult->hasError()) {
182 8
                log_info('[リダイレクト] WarningもしくはErrorが発生したためカート画面へ遷移します.',
183
                    [$flowResult->getWarning(), $flowResult->getErrors()]);
184 12
185 12
                return $this->redirectToRoute('shopping_error');
186
            }
187
188 12
            $redirectTo = $form['redirect_to']->getData();
189 12
            if (empty($redirectTo)) {
190
                log_info('[リダイレクト] リダイレクト先未指定のため注文手続き画面へ遷移します.');
191
192
                return $this->redirectToRoute('shopping');
193
            }
194
195
            try {
196
                // リダイレクト先のチェック.
197
                $result = $router->match($redirectTo);
198
                // パラメータのみ抽出
199
                $params = array_filter($result, function ($key) {
200 5
                    return 0 !== \strpos($key, '_');
201
                }, ARRAY_FILTER_USE_KEY);
202
203 5
                log_info('[リダイレクト] リダイレクトを実行します.', [$result['_route'], $params]);
204 5
205
                // pathからurlを再構築してリダイレクト.
206
                return $this->redirectToRoute($result['_route'], $params);
207
            } catch (\Exception $e) {
208
                log_info('[リダイレクト] URLの形式が不正です', [$redirectTo, $e->getMessage()]);
209 5
210 5
                return $this->redirectToRoute('shopping_error');
211
            }
212
        }
213
214
        log_info('[リダイレクト] フォームエラーのため, 注文手続き画面を表示します.', [$Order->getId()]);
215 5
216 5
        return [
217 5
            'form' => $form->createView(),
218
            'Order' => $Order,
219 5
        ];
220 5
    }
221
222 5
    /**
223 5
     * 注文確認画面を表示する.
224
     *
225
     * ここではPaymentMethod::verifyがコールされます.
226
     * PaymentMethod::verifyではクレジットカードの有効性チェック等, 注文手続きを進められるかどうかのチェック処理を行う事を想定しています.
227 5
     * PaymentMethod::verifyでエラーが発生した場合は, 注文手続き画面へリダイレクトします.
228
     *
229 5
     * @Route("/shopping/confirm", name="shopping_confirm", methods={"POST"})
230
     * @Template("Shopping/confirm.twig")
231 5
     */
232
    public function confirm(Request $request)
233
    {
234
        // ログイン状態のチェック.
235
        if ($this->orderHelper->isLoginRequired()) {
236
            log_info('[注文確認] 未ログインもしくはRememberMeログインのため, ログイン画面に遷移します.');
237
238
            return $this->redirectToRoute('shopping_login');
239
        }
240
241
        // 受注の存在チェック
242
        $preOrderId = $this->cartService->getPreOrderId();
243
        $Order = $this->orderHelper->getPurchaseProcessingOrder($preOrderId);
0 ignored issues
show
Bug introduced by
It seems like $preOrderId defined by $this->cartService->getPreOrderId() on line 242 can also be of type string; however, Eccube\Service\OrderHelp...rchaseProcessingOrder() does only seem to accept null, 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...
244
        if (!$Order) {
245 5
            log_info('[注文確認] 購入処理中の受注が存在しません.', [$preOrderId]);
246
247
            return $this->redirectToRoute('shopping_error');
248 5
        }
249 5
250
        $form = $this->createForm(OrderType::class, $Order);
251
        $form->handleRequest($request);
252
253
        if ($form->isSubmitted() && $form->isValid()) {
254
            log_info('[注文確認] 集計処理を開始します.', [$Order->getId()]);
255
            $flowResult = $this->validatePurchaseFlow($Order);
256
            $this->entityManager->flush();
257
258 View Code Duplication
            if ($flowResult->hasWarning() || $flowResult->hasError()) {
259
                log_info('[注文確認] WarningもしくはErrorが発生したためカート画面へ遷移します.',
260 6
                    [$flowResult->getWarning(), $flowResult->getErrors()]);
261
262
                return $this->redirectToRoute('shopping_error');
263 6
            }
264 6
265
            log_info('[注文確認] PaymentMethod::verifyを実行します.', [$Order->getPayment()->getMethodClass()]);
266
            $paymentMethod = $this->createPaymentMethod($Order, $form);
267
            $PaymentResult = $paymentMethod->verify();
268
269 6
            if ($PaymentResult) {
270 6 View Code Duplication
                if (!$PaymentResult->isSuccess()) {
271
                    $this->entityManager->rollback();
272
                    foreach ($PaymentResult->getErrors() as $error) {
273
                        $this->addError($error);
274
                    }
275
276 6
                    log_info('[注文確認] PaymentMethod::verifyのエラーのため, 注文手続き画面へ遷移します.', [$PaymentResult->getErrors()]);
277
278 6
                    return $this->redirectToRoute('shopping');
279 6
                }
280 6
281
                $response = $PaymentResult->getResponse();
282 6
                if ($response && ($response->isRedirection() || $response->getContent())) {
283 6
                    $this->entityManager->flush();
284
285
                    log_info('[注文確認] PaymentMethod::verifyが指定したレスポンスを表示します.');
286 6
287 6
                    return $response;
288 6
                }
289
            }
290
291
            $this->entityManager->flush();
292
293
            log_info('[注文確認] 注文確認画面を表示します.');
294
295
            return [
296
                'form' => $form->createView(),
297
                'Order' => $Order,
298
            ];
299
        }
300
301
        log_info('[注文確認] フォームエラーのため, 注文手続画面を表示します.', [$Order->getId()]);
302
303
        // FIXME @Templateの差し替え.
304
        $request->attributes->set('_template', new Template(['template' => 'shopping/index.twig']));
305
306
        return [
307
            'form' => $form->createView(),
308
            'Order' => $Order,
309
        ];
310
    }
311
312
    /**
313
     * 注文処理を行う.
314
     *
315
     * 決済プラグインによる決済処理および注文の確定処理を行います.
316
     *
317
     * @Route("/shopping/checkout", name="shopping_checkout", methods={"POST"})
318
     * @Template("Shopping/confirm.twig")
319
     */
320
    public function checkout(Request $request)
321
    {
322
        // ログイン状態のチェック.
323
        if ($this->orderHelper->isLoginRequired()) {
324
            log_info('[注文処理] 未ログインもしくはRememberMeログインのため, ログイン画面に遷移します.');
325
326
            return $this->redirectToRoute('shopping_login');
327
        }
328
329
        // 受注の存在チェック
330
        $preOrderId = $this->cartService->getPreOrderId();
331
        $Order = $this->orderHelper->getPurchaseProcessingOrder($preOrderId);
0 ignored issues
show
Bug introduced by
It seems like $preOrderId defined by $this->cartService->getPreOrderId() on line 330 can also be of type string; however, Eccube\Service\OrderHelp...rchaseProcessingOrder() does only seem to accept null, 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...
332
        if (!$Order) {
333
            log_info('[注文処理] 購入処理中の受注が存在しません.', [$preOrderId]);
334 1
335
            return $this->redirectToRoute('shopping_error');
336
        }
337 1
338
        // フォームの生成.
339 1
        $form = $this->createForm(OrderType::class, $Order);
340
        $form->handleRequest($request);
341
342
        if ($form->isSubmitted() && $form->isValid()) {
343 1
            log_info('[注文処理] 注文処理を開始します.', [$Order->getId()]);
344
345 1
            try {
346
                /**
347 1
                 * 集計処理
348
                 */
349 1
                log_info('[注文処理] 集計処理を開始します.', [$Order->getId()]);
350
                $flowResult = $this->validatePurchaseFlow($Order);
351 1
                $this->entityManager->flush();
352
353 1 View Code Duplication
                if ($flowResult->hasWarning() || $flowResult->hasError()) {
354
                    log_info('[注文処理] WarningもしくはErrorが発生したためカート画面へ遷移します.',
355
                        [$flowResult->getWarning(), $flowResult->getErrors()]);
356
357
                    return $this->redirectToRoute('shopping_error');
358 1
                }
359 1
360 1
                /**
361
                 * 決済実行(前処理)
362 1
                 */
363
                log_info('[注文処理] PaymentMethod::applyを実行します.', [$Order->getPayment()->getMethodClass()]);
364 1
                $paymentMethod = $this->createPaymentMethod($Order, $form);
365
                $dispatcher = $paymentMethod->apply(); // 決済処理中.
366
367 1
                // リンク式決済のように他のサイトへ遷移する場合などは, dispatcherに処理を移譲する.
368 1
                if ($dispatcher instanceof PaymentDispatcher) {
369
                    $response = $dispatcher->getResponse();
370
                    $this->entityManager->flush();
371
372
                    // dispatcherがresponseを保持している場合はresponseを返す
373
                    if ($response && ($response->isRedirection() || $response->getContent())) {
374
                        log_info('[注文処理] PaymentMethod::applyが指定したレスポンスを表示します.');
375
376
                        return $response;
377
                    }
378
379
                    // forwardすることも可能.
380
                    if ($dispatcher->isForward()) {
381
                        log_info('[注文処理] PaymentMethod::applyによりForwardします.', [
382
                            $dispatcher->getRoute(),
383
                            $dispatcher->getPathParameters(),
384
                            $dispatcher->getQueryParameters(),
385
                        ]);
386
387
                        return $this->forwardToRoute($dispatcher->getRoute(), $dispatcher->getPathParameters(),
388
                            $dispatcher->getQueryParameters());
389
                    } else {
390
                        log_info('[注文処理] PaymentMethod::applyによりリダイレクトします.', [
391
                            $dispatcher->getRoute(),
392
                            $dispatcher->getPathParameters(),
393
                            $dispatcher->getQueryParameters(),
394
                        ]);
395
396
                        return $this->redirectToRoute($dispatcher->getRoute(),
397
                            array_merge($dispatcher->getPathParameters(), $dispatcher->getQueryParameters()));
398
                    }
399
                }
400
401
                /**
402
                 * 決済実行
403
                 *
404
                 * PaymentMethod::checkoutでは決済処理が行われ, 正常に処理出来た場合はPurchaseFlow::commitがコールされます.
405
                 */
406
                log_info('[注文処理] PaymentMethod::checkoutを実行します.', [$Order->getPayment()->getMethodClass()]);
407
                $PaymentResult = $paymentMethod->checkout();
408
                $response = $PaymentResult->getResponse();
409
                // PaymentResultがresponseを保持している場合はresponseを返す
410
                if ($response && ($response->isRedirection() || $response->getContent())) {
411
                    log_info('[注文処理] PaymentMethod::checkoutが指定したレスポンスを表示します.');
412
413
                    return $response;
414
                }
415
416
                // エラー時はロールバックして購入エラーとする.
417 View Code Duplication
                if (!$PaymentResult->isSuccess()) {
418
                    $this->entityManager->rollback();
419
                    foreach ($PaymentResult->getErrors() as $error) {
420
                        $this->addError($error);
421
                    }
422
423
                    log_info('[注文処理] PaymentMethod::checkoutのエラーのため, 購入エラー画面へ遷移します.', [$PaymentResult->getErrors()]);
424
425
                    return $this->redirectToRoute('shopping_error');
426
                }
427
428
                $this->entityManager->flush();
429
430
                log_info('[注文処理] 注文処理が完了しました.', [$Order->getId()]);
431
            } catch (ShoppingException $e) {
432
                log_error('[注文処理] 購入エラーが発生しました.', [$e->getMessage()]);
433
434
                $this->entityManager->rollback();
435
436
                $this->addError($e->getMessage());
437
438
                return $this->redirectToRoute('shopping_error');
439
            } catch (\Exception $e) {
440
                log_error('[注文確認] 予期しないエラーが発生しました.', [$e->getMessage()]);
441
442
                $this->entityManager->rollback();
443
444
                $this->addError('front.shopping.system_error');
445
446
                return $this->redirectToRoute('shopping_error');
447
            }
448
449
            // カート削除
450
            log_info('[注文処理] カートをクリアします.', [$Order->getId()]);
451
            $this->cartService->clear();
452
453
            // 受注IDをセッションにセット
454
            $this->session->set(OrderHelper::SESSION_ORDER_ID, $Order->getId());
455
456
            // メール送信
457
            log_info('[注文処理] 注文メールの送信を行います.', [$Order->getId()]);
458
            $this->mailService->sendOrderMail($Order);
459
460
            log_info('[注文処理] 注文処理が完了しました. 購入完了画面へ遷移します.', [$Order->getId()]);
461
462
            return $this->redirectToRoute('shopping_complete');
463
        }
464
465
        log_info('[注文処理] フォームエラーのため, 購入エラー画面へ遷移します.', [$Order->getId()]);
466
467
        return $this->redirectToRoute('shopping_error');
468
    }
469
470
    /**
471
     * 購入完了画面を表示する.
472
     *
473
     * @Route("/shopping/complete", name="shopping_complete")
474
     * @Template("Shopping/complete.twig")
475
     */
476
    public function complete(Request $request)
477
    {
478
        log_info('[注文完了] 注文完了画面を表示します.');
479
480
        // 受注IDを取得
481
        $orderId = $this->session->get(OrderHelper::SESSION_ORDER_ID);
482
483
        if (empty($orderId)) {
484
            log_info('[注文完了] 受注IDを取得できないため, トップページへ遷移します.');
485
486
            return $this->redirectToRoute('homepage');
487
        }
488
489
        $Order = $this->orderRepository->find($orderId);
490
491
        $event = new EventArgs(
492
            [
493
                'Order' => $Order,
494
            ],
495
            $request
496
        );
497
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_SHOPPING_COMPLETE_INITIALIZE, $event);
498
499
        if ($event->getResponse() !== null) {
500
            return $event->getResponse();
501
        }
502
503
        log_info('[注文完了] 購入フローのセッションをクリアします. ');
504
        $this->orderHelper->removeSession();
505
506
        $hasNextCart = !empty($this->cartService->getCarts());
507
508
        log_info('[注文完了] 注文完了画面を表示しました. ', [$hasNextCart]);
509
510
        return [
511
            'Order' => $Order,
512
            'hasNextCart' => $hasNextCart,
513
        ];
514
    }
515
516
    /**
517
     * お届け先選択画面.
518
     *
519
     * 会員ログイン時, お届け先を選択する画面を表示する
520
     * 非会員の場合はこの画面は使用しない。
521
     *
522
     * @Route("/shopping/shipping/{id}", name="shopping_shipping", requirements={"id" = "\d+"})
523
     * @Template("Shopping/shipping.twig")
524
     */
525
    public function shipping(Request $request, Shipping $Shipping)
526
    {
527
        // ログイン状態のチェック.
528
        if ($this->orderHelper->isLoginRequired()) {
529
            return $this->redirectToRoute('shopping_login');
530
        }
531
532
        // 受注の存在チェック
533
        $preOrderId = $this->cartService->getPreOrderId();
534
        $Order = $this->orderHelper->getPurchaseProcessingOrder($preOrderId);
0 ignored issues
show
Bug introduced by
It seems like $preOrderId defined by $this->cartService->getPreOrderId() on line 533 can also be of type string; however, Eccube\Service\OrderHelp...rchaseProcessingOrder() does only seem to accept null, 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...
535
        if (!$Order) {
536
            return $this->redirectToRoute('shopping_error');
537
        }
538
539
        // 受注に紐づくShippingかどうかのチェック.
540
        if (!$Order->findShipping($Shipping->getId())) {
541
            return $this->redirectToRoute('shopping_error');
542
        }
543
544
        $builder = $this->formFactory->createBuilder(CustomerAddressType::class, null, [
545
            'customer' => $this->getUser(),
546
            'shipping' => $Shipping,
547
        ]);
548
549
        $form = $builder->getForm();
550
        $form->handleRequest($request);
551
552
        if ($form->isSubmitted() && $form->isValid()) {
553
            log_info('お届先情報更新開始', [$Shipping->getId()]);
554
555
            /** @var CustomerAddress $CustomerAddress */
556
            $CustomerAddress = $form['addresses']->getData();
557
558
            // お届け先情報を更新
559
            $Shipping->setFromCustomerAddress($CustomerAddress);
560
561
            // 合計金額の再計算
562
            $flowResult = $this->validatePurchaseFlow($Order);
563
            $this->entityManager->flush();
564
565
            if ($flowResult->hasWarning() || $flowResult->hasError()) {
566
                return $this->redirectToRoute('shopping_error');
567
            }
568 2
569
            $event = new EventArgs(
570 2
                [
571
                    'Order' => $Order,
572
                    'Shipping' => $Shipping,
573
                ],
574
                $request
575 2
            );
576
            $this->eventDispatcher->dispatch(EccubeEvents::FRONT_SHOPPING_SHIPPING_COMPLETE, $event);
577 2
578
            log_info('お届先情報更新完了', [$Shipping->getId()]);
579
580
            return $this->redirectToRoute('shopping');
581
        }
582
583
        return [
584 2
            'form' => $form->createView(),
585
            'Customer' => $this->getUser(),
586 2
            'shippingId' => $Shipping->getId(),
587
        ];
588 2
    }
589
590 2
    /**
591
     * お届け先の新規作成または編集画面.
592 2
     *
593
     * 会員時は新しいお届け先を作成する.
594
     * 非会員時は選択されたお届け先の編集を行う.
595 2
     *
596 2
     * @Route("/shopping/shipping_edit/{id}", name="shopping_shipping_edit", requirements={"id" = "\d+"})
597
     * @Template("Shopping/shipping_edit.twig")
598
     */
599
    public function shippingEdit(Request $request, Shipping $Shipping)
600
    {
601
        // ログイン状態のチェック.
602
        if ($this->orderHelper->isLoginRequired()) {
603
            return $this->redirectToRoute('shopping_login');
604
        }
605
606 1
        // 受注の存在チェック
607
        $preOrderId = $this->cartService->getPreOrderId();
608 1
        $Order = $this->orderHelper->getPurchaseProcessingOrder($preOrderId);
0 ignored issues
show
Bug introduced by
It seems like $preOrderId defined by $this->cartService->getPreOrderId() on line 607 can also be of type string; however, Eccube\Service\OrderHelp...rchaseProcessingOrder() does only seem to accept null, 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...
609 1
        if (!$Order) {
610 1
            return $this->redirectToRoute('shopping_error');
611
        }
612 1
613
        // 受注に紐づくShippingかどうかのチェック.
614 1
        if (!$Order->findShipping($Shipping->getId())) {
615
            return $this->redirectToRoute('shopping_error');
616
        }
617
618 1
        $CustomerAddress = new CustomerAddress();
619
        if ($this->isGranted('IS_AUTHENTICATED_FULLY')) {
620
            // ログイン時は会員と紐付け
621
            $CustomerAddress->setCustomer($this->getUser());
622
        } else {
623
            // 非会員時はお届け先をセット
624
            $CustomerAddress->setFromShipping($Shipping);
625
        }
626
        $builder = $this->formFactory->createBuilder(ShoppingShippingType::class, $CustomerAddress);
627 55
628
        $event = new EventArgs(
629 55
            [
630 55
                'builder' => $builder,
631 53
                'Order' => $Order,
632 53
                'Shipping' => $Shipping,
633
                'CustomerAddress' => $CustomerAddress,
634
            ],
635
            $request
636
        );
637
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_SHOPPING_SHIPPING_EDIT_INITIALIZE, $event);
638 53
639
        $form = $builder->getForm();
640 2
        $form->handleRequest($request);
641
642
        if ($form->isSubmitted() && $form->isValid()) {
643 2
            log_info('お届け先追加処理開始', ['order_id' => $Order->getId(), 'shipping_id' => $Shipping->getId()]);
644
645
            $Shipping->setFromCustomerAddress($CustomerAddress);
646
647
            if ($this->isGranted('IS_AUTHENTICATED_FULLY')) {
648
                $this->entityManager->persist($CustomerAddress);
649
            }
650
651
            // 合計金額の再計算
652 50
            $flowResult = $this->validatePurchaseFlow($Order);
653
            $this->entityManager->flush();
654
            if ($flowResult->hasWarning() || $flowResult->hasError()) {
655 50
                return $this->redirectToRoute('shopping_error');
656
            }
657
658 50
            $event = new EventArgs(
659
                [
660 34
                    'form' => $form,
661
                    'Shipping' => $Shipping,
662
                    'CustomerAddress' => $CustomerAddress,
663
                ],
664
                $request
665
            );
666
            $this->eventDispatcher->dispatch(EccubeEvents::FRONT_SHOPPING_SHIPPING_EDIT_COMPLETE, $event);
667
668
            log_info('お届け先追加処理完了', ['order_id' => $Order->getId(), 'shipping_id' => $Shipping->getId()]);
669
670 34
            return $this->redirectToRoute('shopping');
671
        }
672
673
        return [
674
            'form' => $form->createView(),
675
            'shippingId' => $Shipping->getId(),
676 34
        ];
677 34
    }
678 34
679
    /**
680 34
     * ログイン画面.
681 34
     *
682
     * @Route("/shopping/login", name="shopping_login")
683
     * @Template("Shopping/login.twig")
684
     */
685
    public function login(Request $request, AuthenticationUtils $authenticationUtils)
686
    {
687
        if ($this->isGranted('IS_AUTHENTICATED_FULLY')) {
688
            return $this->redirectToRoute('shopping');
689
        }
690 34
691
        /* @var $form \Symfony\Component\Form\FormInterface */
692
        $builder = $this->formFactory->createNamedBuilder('', CustomerLoginType::class);
693
694 50
        if ($this->isGranted('IS_AUTHENTICATED_REMEMBERED')) {
695
            $Customer = $this->getUser();
696 50
            if ($Customer) {
697
                $builder->get('login_email')->setData($Customer->getEmail());
698 50
            }
699
        }
700
701
        $event = new EventArgs(
702
            [
703
                'builder' => $builder,
704
            ],
705
            $request
706
        );
707 50
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_SHOPPING_LOGIN_INITIALIZE, $event);
708
709 50
        $form = $builder->getForm();
710
711 50
        return [
712
            'error' => $authenticationUtils->getLastAuthenticationError(),
713 50
            'form' => $form->createView(),
714
        ];
715 50
    }
716 50
717
    /**
718 50
     * 購入エラー画面.
719
     *
720 50
     * @Route("/shopping/error", name="shopping_error")
721
     * @Template("Shopping/shopping_error.twig")
722 50
     */
723
    public function error(Request $request, PurchaseFlow $cartPurchaseFlow)
724 50
    {
725
        // 受注とカートのずれを合わせるため, カートのPurchaseFlowをコールする.
726 50
        $Cart = $this->cartService->getCart();
727
        if (null !== $Cart) {
728
            $cartPurchaseFlow->validate($Cart, new PurchaseContext());
0 ignored issues
show
Security Bug introduced by
It seems like $Cart defined by $this->cartService->getCart() on line 726 can also be of type false; however, Eccube\Service\PurchaseF...urchaseFlow::validate() does only seem to accept object<Eccube\Entity\ItemHolderInterface>, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
729
            $this->cartService->save();
730
        }
731
732
        $event = new EventArgs(
733
            [],
734
            $request
735 20
        );
736
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_SHOPPING_SHIPPING_ERROR_COMPLETE, $event);
737 20
738
        if ($event->getResponse() !== null) {
739
            return $event->getResponse();
740
        }
741
742
        return [];
743 20
    }
744
745 8
    /**
746
     * PaymentMethodをコンテナから取得する.
747 8
     *
748 8
     * @param Order $Order
749 7
     * @param FormInterface $form
750
     *
751 1
     * @return PaymentMethodInterface
752
     */
753 1
    private function createPaymentMethod(Order $Order, FormInterface $form)
754 7
    {
755
        $PaymentMethod = $this->container->get($Order->getPayment()->getMethodClass());
756
        $PaymentMethod->setOrder($Order);
757
        $PaymentMethod->setFormType($form);
758
759 7
        return $PaymentMethod;
760
    }
761
}
762