Failed Conditions
Pull Request — experimental/sf (#3236)
by Kentaro
144:19 queued 116:23
created

Eccube/Controller/NonMemberShoppingController.php (1 issue)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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\Customer;
17
use Eccube\Entity\Master\OrderStatus;
18
use Eccube\Entity\Order;
19
use Eccube\Event\EccubeEvents;
20
use Eccube\Event\EventArgs;
21
use Eccube\Exception\CartException;
22
use Eccube\Form\Type\Front\NonMemberType;
23
use Eccube\Repository\Master\PrefRepository;
24
use Eccube\Service\CartService;
25
use Eccube\Service\OrderHelper;
26
use Eccube\Service\ShoppingService;
27
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
28
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
29
use Symfony\Component\HttpFoundation\Request;
30
use Symfony\Component\Validator\Constraints as Assert;
31
use Symfony\Component\Validator\Validator\ValidatorInterface;
32
33
class NonMemberShoppingController extends AbstractShoppingController
34
{
35
    /**
36
     * @var ValidatorInterface
37
     */
38
    protected $validator;
39
40
    /**
41
     * @var PrefRepository
42
     */
43
    protected $prefRepository;
44
45
    /**
46
     * @var OrderHelper
47
     */
48
    protected $orderHelper;
49
50
    /**
51
     * @var ShoppingService
52
     */
53
    protected $shoppingService;
54
55
    /**
56
     * @var CartService
57
     */
58
    protected $cartService;
59
60
    /**
61
     * NonMemberShoppingController constructor.
62
     *
63
     * @param ValidatorInterface $validator
64
     * @param PrefRepository $prefRepository
65
     * @param OrderHelper $orderHelper
66
     * @param ShoppingService $shoppingService
67
     * @param CartService $cartService
68
     */
69 20
    public function __construct(
70
        ValidatorInterface $validator,
71
        PrefRepository $prefRepository,
72
        OrderHelper $orderHelper,
73
        ShoppingService $shoppingService,
74
        CartService $cartService
75
    ) {
76 20
        $this->validator = $validator;
77 20
        $this->prefRepository = $prefRepository;
78 20
        $this->orderHelper = $orderHelper;
79 20
        $this->shoppingService = $shoppingService;
80 20
        $this->cartService = $cartService;
81
    }
82
83
    /**
84
     * 非会員処理
85
     *
86
     * @Route("/shopping/nonmember", name="shopping_nonmember")
87
     * @Template("Shopping/nonmember.twig")
88
     */
89 20
    public function index(Request $request)
90
    {
91 20
        $cartService = $this->cartService;
92
93
        // カートチェック
94 20
        $response = $this->forwardToRoute('shopping_check_to_cart');
95 20
        if ($response->isRedirection() || $response->getContent()) {
96 1
            return $response;
97
        }
98
99
        // ログイン済みの場合は, 購入画面へリダイレクト.
100 19
        if ($this->isGranted('ROLE_USER')) {
101 1
            return $this->redirectToRoute('shopping');
102
        }
103
104 18
        $builder = $this->formFactory->createBuilder(NonMemberType::class);
105
106 18
        $event = new EventArgs(
107
            [
108 18
                'builder' => $builder,
109
            ],
110 18
            $request
111
        );
112 18
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_SHOPPING_NONMEMBER_INITIALIZE, $event);
113
114 18
        $form = $builder->getForm();
115
116 18
        $form->handleRequest($request);
117
118 18
        if ($form->isSubmitted() && $form->isValid()) {
119 17
            log_info('非会員お客様情報登録開始');
120
121 17
            $data = $form->getData();
122 17
            $Customer = new Customer();
123
            $Customer
124 17
                ->setName01($data['name01'])
125 17
                ->setName02($data['name02'])
126 17
                ->setKana01($data['kana01'])
127 17
                ->setKana02($data['kana02'])
128 17
                ->setCompanyName($data['company_name'])
129 17
                ->setEmail($data['email'])
130 17
                ->setPhonenumber($data['phone_number'])
131 17
                ->setPostalcode($data['postal_code'])
132 17
                ->setPref($data['pref'])
133 17
                ->setAddr01($data['addr01'])
134 17
                ->setAddr02($data['addr02']);
135
136
            // 受注情報を取得
137
            /** @var Order $Order */
138 17
            $Order = $this->shoppingService->getOrder(OrderStatus::PROCESSING);
139
140
            // 初回アクセス(受注データがない)の場合は, 受注情報を作成
141 17
            if (is_null($Order)) {
142
                // 受注情報を作成
143
                try {
144
                    // 受注情報を作成
145 17
                    $Order = $this->orderHelper->createProcessingOrder(
146 17
                        $Customer,
147 17
                        $cartService->getCart()->getCartItems()
0 ignored issues
show
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...
148
                    );
149 17
                    $cartService->setPreOrderId($Order->getPreOrderId());
150 17
                    $cartService->save();
151
                } catch (CartException $e) {
152
                    $this->addRequestError($e->getMessage());
153
154
                    return $this->redirectToRoute('cart');
155
                }
156
            }
157
158 17
            $flowResult = $this->validatePurchaseFlow($Order);
159 17
            if ($flowResult->hasWarning() || $flowResult->hasError()) {
160
                return $this->redirectToRoute('cart');
161
            }
162
163
            // 非会員用セッションを作成
164 17
            $this->session->set($this->sessionKey, $Customer);
165 17
            $this->session->set($this->sessionCustomerAddressKey, serialize([]));
166
167 17
            $event = new EventArgs(
168
                [
169 17
                    'form' => $form,
170 17
                    'Order' => $Order,
171
                ],
172 17
                $request
173
            );
174 17
            $this->eventDispatcher->dispatch(EccubeEvents::FRONT_SHOPPING_NONMEMBER_COMPLETE, $event);
175
176 17
            if ($event->getResponse() !== null) {
177
                return $event->getResponse();
178
            }
179
180 17
            log_info('非会員お客様情報登録完了', [$Order->getId()]);
181
182 17
            return $this->redirectToRoute('shopping');
183
        }
184
185
        return [
186 1
            'form' => $form->createView(),
187
        ];
188
    }
189
190
    /**
191
     * お届け先の設定(非会員)がクリックされた場合の処理
192
     *
193
     * @Route("/shopping/shipping_edit_change/{id}", name="shopping_shipping_edit_change", requirements={"id" = "\d+"})
194
     */
195
    public function shippingEditChange(Request $request, $id)
196
    {
197
        $Order = $this->shoppingService->getOrder(OrderStatus::PROCESSING);
198
        if (!$Order) {
199
            $this->addError('front.shopping.order.error');
200
201
            return $this->redirectToRoute('shopping_error');
202
        }
203
204
        if ('POST' !== $request->getMethod()) {
205
            return $this->redirectToRoute('shopping');
206
        }
207
208
        $builder = $this->shoppingService->getShippingFormBuilder($Order);
209
210
        $event = new EventArgs(
211
            [
212
                'builder' => $builder,
213
                'Order' => $Order,
214
            ],
215
            $request
216
        );
217
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_SHOPPING_SHIPPING_EDIT_CHANGE_INITIALIZE, $event);
218
219
        $form = $builder->getForm();
220
221
        $form->handleRequest($request);
222
223
        if ($form->isSubmitted() && $form->isValid()) {
224
            $data = $form->getData();
225
            $message = $data['message'];
226
            $Order->setMessage($message);
227
            // 受注情報を更新
228
            $this->entityManager->flush();
229
230
            // お届け先設定一覧へリダイレクト
231
            return $this->redirectToRoute('shopping_shipping_edit', ['id' => $id]);
232
        }
233
234
        return $this->redirectToRoute('Shopping/index.twig', [
235
            'form' => $form->createView(),
236
            'Order' => $Order,
237
        ]);
238
    }
239
240
    /**
241
     * お客様情報の変更(非会員)
242
     *
243
     * @Route("/shopping/customer", name="shopping_customer")
244
     */
245
    public function customer(Request $request)
246
    {
247
        if (!$request->isXmlHttpRequest()) {
248
            return $this->json(['status' => 'NG'], 400);
249
        }
250
        try {
251
            log_info('非会員お客様情報変更処理開始');
252
            $data = $request->request->all();
253
            // 入力チェック
254
            $errors = $this->customerValidation($data);
255
            foreach ($errors as $error) {
256
                if ($error->count() != 0) {
257
                    log_info('非会員お客様情報変更入力チェックエラー');
258
259
                    return $this->json(['status' => 'NG'], 400);
260
                }
261
            }
262
            $pref = $this->prefRepository->findOneBy(['name' => $data['customer_pref']]);
263
            if (!$pref) {
264
                log_info('非会員お客様情報変更入力チェックエラー');
265
266
                return $this->json(['status' => 'NG'], 400);
267
            }
268
            /** @var Order $Order */
269
            $Order = $this->shoppingService->getOrder(OrderStatus::PROCESSING);
270
            if (!$Order) {
271
                log_info('カートが存在しません');
272
                $this->addError('front.shopping.order.error');
273
274
                return $this->redirectToRoute('shopping_error');
275
            }
276
            $Order
277
                ->setName01($data['customer_name01'])
278
                ->setName02($data['customer_name02'])
279
                ->setKana01($data['customer_kana01'])
280
                ->setKana02($data['customer_kana02'])
281
                ->setCompanyName($data['customer_company_name'])
282
                ->setPhoneNumber($data['customer_phone_number'])
283
                ->setPostalCode($data['customer_postal_code'])
284
                ->setPref($pref)
285
                ->setAddr01($data['customer_addr01'])
286
                ->setAddr02($data['customer_addr02'])
287
                ->setEmail($data['customer_email']);
288
            // 配送先を更新
289
            $this->entityManager->flush();
290
            // 受注関連情報を最新状態に更新
291
            $this->entityManager->refresh($Order);
292
            $event = new EventArgs(
293
                [
294
                    'Order' => $Order,
295
                    'data' => $data,
296
                ],
297
                $request
298
            );
299
            $this->eventDispatcher->dispatch(EccubeEvents::FRONT_SHOPPING_CUSTOMER_INITIALIZE, $event);
300
            log_info('非会員お客様情報変更処理完了', [$Order->getId()]);
301
            $message = ['status' => 'OK', 'kana01' => $data['customer_kana01'], 'kana02' => $data['customer_kana02']];
302
303
            $response = $this->json($message);
304
        } catch (\Exception $e) {
305
            log_error('予期しないエラー', [$e->getMessage()]);
306
307
            $response = $this->json(['status' => 'NG'], 500);
308
        }
309
310
        return $response;
311
    }
312
313
    /**
314
     * 非会員でのお客様情報変更時の入力チェック
315
     *
316
     * @param array $data リクエストパラメータ
317
     *
318
     * @return \Symfony\Component\Validator\ConstraintViolationListInterface[]
319
     */
320
    protected function customerValidation(array &$data)
321
    {
322
        // 入力チェック
323
        $errors = [];
324
325
        $errors[] = $this->validator->validate(
326
            $data['customer_name01'],
327
            [
328
                new Assert\NotBlank(),
329
                new Assert\Length(['max' => $this->eccubeConfig['eccube_name_len']]),
330
                new Assert\Regex(
331
                    ['pattern' => '/^[^\s ]+$/u', 'message' => 'form.type.name.firstname.nothasspace']
332
                ),
333
            ]
334
        );
335
336
        $errors[] = $this->validator->validate(
337
            $data['customer_name02'],
338
            [
339
                new Assert\NotBlank(),
340
                new Assert\Length(['max' => $this->eccubeConfig['eccube_name_len']]),
341
                new Assert\Regex(
342
                    ['pattern' => '/^[^\s ]+$/u', 'message' => 'form.type.name.firstname.nothasspace']
343
                ),
344
            ]
345
        );
346
347
        $data['customer_kana01'] = mb_convert_kana($data['customer_kana01'], 'CV', 'utf-8');
348
        $errors[] = $this->validator->validate(
349
            $data['customer_kana01'],
350
            [
351
                new Assert\NotBlank(),
352
                new Assert\Length(['max' => $this->eccubeConfig['eccube_kana_len']]),
353
                new Assert\Regex(['pattern' => '/^[ァ-ヶヲ-゚ー]+$/u']),
354
            ]
355
        );
356
        $data['customer_kana02'] = mb_convert_kana($data['customer_kana02'], 'CV', 'utf-8');
357
        $errors[] = $this->validator->validate(
358
            $data['customer_kana02'],
359
            [
360
                new Assert\NotBlank(),
361
                new Assert\Length(['max' => $this->eccubeConfig['eccube_kana_len']]),
362
                new Assert\Regex(['pattern' => '/^[ァ-ヶヲ-゚ー]+$/u']),
363
        ]);
364
365
        $errors[] = $this->validator->validate(
366
            $data['customer_company_name'],
367
            [
368
                new Assert\Length(['max' => $this->eccubeConfig['eccube_stext_len']]),
369
            ]
370
        );
371
372
        $errors[] = $this->validator->validate(
373
            $data['customer_phone_number'],
374
            [
375
                new Assert\NotBlank(),
376
                new Assert\Type(['type' => 'numeric', 'message' => 'form.type.numeric.invalid']),
377
                new Assert\Length(
378
                    ['max' => $this->eccubeConfig['eccube_tel_len_max']]
379
                ),
380
            ]
381
        );
382
383
        $errors[] = $this->validator->validate(
384
            $data['customer_postal_code'],
385
            [
386
                new Assert\NotBlank(),
387
                new Assert\Type(['type' => 'numeric', 'message' => 'form.type.numeric.invalid']),
388
                new Assert\Length(
389
                    ['max' => $this->eccubeConfig['eccube_postal_code']]
390
                ),
391
            ]
392
        );
393
394
        $errors[] = $this->validator->validate(
395
            $data['customer_addr01'],
396
            [
397
                new Assert\NotBlank(),
398
                new Assert\Length(['max' => $this->eccubeConfig['eccube_address1_len']]),
399
            ]
400
        );
401
402
        $errors[] = $this->validator->validate(
403
            $data['customer_addr02'],
404
            [
405
                new Assert\NotBlank(),
406
                new Assert\Length(['max' => $this->eccubeConfig['eccube_address2_len']]),
407
            ]
408
        );
409
410
        $errors[] = $this->validator->validate(
411
            $data['customer_email'],
412
            [
413
                new Assert\NotBlank(),
414
                new Assert\Email(['strict' => true]),
415
            ]
416
        );
417
418
        return $errors;
419
    }
420
}
421