Failed Conditions
Pull Request — experimental/3.1 (#2641)
by Kiyotaka
53:23
created

ProductController::addCart()   C

Complexity

Conditions 7
Paths 12

Size

Total Lines 91
Code Lines 53

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 16.8299

Importance

Changes 0
Metric Value
cc 7
eloc 53
nc 12
nop 3
dl 0
loc 91
ccs 17
cts 41
cp 0.4146
crap 16.8299
rs 6.5033
c 0
b 0
f 0

How to fix   Long Method   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
/*
3
 * This file is part of EC-CUBE
4
 *
5
 * Copyright(c) 2000-2015 LOCKON CO.,LTD. All Rights Reserved.
6
 *
7
 * http://www.lockon.co.jp/
8
 *
9
 * This program is free software; you can redistribute it and/or
10
 * modify it under the terms of the GNU General Public License
11
 * as published by the Free Software Foundation; either version 2
12
 * of the License, or (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 * GNU General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU General Public License
20
 * along with this program; if not, write to the Free Software
21
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22
 */
23
24
25
namespace Eccube\Controller;
26
27
use Doctrine\ORM\EntityManager;
28
use Eccube\Annotation\Inject;
29
use Eccube\Application;
30
use Eccube\Entity\BaseInfo;
31
use Eccube\Entity\Master\ProductStatus;
32
use Eccube\Entity\Product;
33
use Eccube\Event\EccubeEvents;
34
use Eccube\Event\EventArgs;
35
use Eccube\Exception\CartException;
36
use Eccube\Form\Type\AddCartType;
37
use Eccube\Form\Type\Master\ProductListMaxType;
38
use Eccube\Form\Type\Master\ProductListOrderByType;
39
use Eccube\Form\Type\SearchProductType;
40
use Eccube\Repository\CustomerFavoriteProductRepository;
41
use Eccube\Repository\ProductRepository;
42
use Eccube\Service\CartService;
43
use Eccube\Service\PurchaseFlow\PurchaseFlow;
44
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
45
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
46
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
47
use Symfony\Component\EventDispatcher\EventDispatcher;
48
use Symfony\Component\Form\FormFactory;
49
use Symfony\Component\HttpFoundation\Request;
50
use Symfony\Component\HttpFoundation\Session\Session;
51
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
52
53
/**
54
 * @Route(service=ProductController::class)
55
 */
56
class ProductController
57
{
58
    /**
59
     * @Inject("eccube.purchase.flow.cart")
60
     * @var PurchaseFlow
61
     */
62
    protected $purchaseFlow;
63
64
    /**
65
     * @Inject("session")
66
     * @var Session
67
     */
68
    protected $session;
69
70
    /**
71
     * @Inject(CustomerFavoriteProductRepository::class)
72
     * @var CustomerFavoriteProductRepository
73
     */
74
    protected $customerFavoriteProductRepository;
75
76
    /**
77
     * @Inject(CartService::class)
78
     * @var CartService
79
     */
80
    protected $cartService;
81
82
    /**
83
     * @Inject(ProductRepository::class)
84
     * @var ProductRepository
85
     */
86
    protected $productRepository;
87
88
    /**
89
     * @Inject("eccube.event.dispatcher")
90
     * @var EventDispatcher
91
     */
92
    protected $eventDispatcher;
93
94
    /**
95
     * @Inject("form.factory")
96
     * @var FormFactory
97
     */
98
    protected $formFactory;
99
100
    /**
101
     * @Inject("orm.em")
102
     * @var EntityManager
103
     */
104
    protected $entityManager;
105
106
    /**
107
     * @Inject(BaseInfo::class)
108
     * @var BaseInfo
109
     */
110
    protected $BaseInfo;
111
112
    private $title;
113
114
    public function __construct()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
115
    {
116
        $this->title = '';
117
    }
118
119
    /**
0 ignored issues
show
introduced by
Doc comment for parameter "$app" missing
Loading history...
introduced by
Doc comment for parameter "$request" missing
Loading history...
120
     * 商品一覧画面.
121
     *
122
     * @Route("/products/list", name="product_list")
123
     * @Template("Product/list.twig")
124
     */
0 ignored issues
show
introduced by
Missing @return tag in function comment
Loading history...
125
    public function index(Application $app, Request $request)
126
    {
127 3
        // Doctrine SQLFilter
128
        if ($this->BaseInfo->isNostockHidden()) {
129
            $this->entityManager->getFilters()->enable('nostock_hidden');
130 3
        }
131
132
        // handleRequestは空のqueryの場合は無視するため
133
        if ($request->getMethod() === 'GET') {
134
            $request->query->set('pageno', $request->query->get('pageno', ''));
135 3
        }
136 3
137
        // searchForm
138
        /* @var $builder \Symfony\Component\Form\FormBuilderInterface */
139
        $builder = $this->formFactory->createNamedBuilder('', SearchProductType::class);
140
        $builder->setAttribute('freeze', true);
141 3
        $builder->setAttribute('freeze_display_text', false);
142 3
        if ($request->getMethod() === 'GET') {
143 3
            $builder->setMethod('GET');
144 3
        }
145 3
146
        $event = new EventArgs(
147
            array(
148 3
                'builder' => $builder,
149
            ),
150 3
            $request
151
        );
152 3
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_PRODUCT_INDEX_INITIALIZE, $event);
153
154 3
        /* @var $searchForm \Symfony\Component\Form\FormInterface */
155
        $searchForm = $builder->getForm();
156
157 3
        $searchForm->handleRequest($request);
158
159 3
        // paginator
160
        $searchData = $searchForm->getData();
161
        $qb = $this->productRepository->getQueryBuilderBySearchData($searchData);
162 3
163 3
        $event = new EventArgs(
164
            array(
165 3
                'searchData' => $searchData,
166
                'qb' => $qb,
167 3
            ),
168 3
            $request
169
        );
170 3
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_PRODUCT_INDEX_SEARCH, $event);
171
        $searchData = $event->getArgument('searchData');
172 3
173 3
        $pagination = $app['paginator']()->paginate(
174
            $qb,
175 3
            !empty($searchData['pageno']) ? $searchData['pageno'] : 1,
176 3
            $searchData['disp_number']->getId()
177 3
        );
178 3
179
        // addCart form
180
        $forms = array();
181
        foreach ($pagination as $Product) {
182 3
            /* @var $builder \Symfony\Component\Form\FormBuilderInterface */
183 3
            $builder = $this->formFactory->createNamedBuilder(
184
                '',
185 3
                AddCartType::class,
186 3
                null,
187 3
                array(
188 3
                    'product' => $Product,
189
                    'allow_extra_fields' => true,
190 3
                )
191
            );
192
            $addCartForm = $builder->getForm();
193
194 3
            if ($request->getMethod() === 'POST' && (string)$Product->getId() === $request->get('product_id')) {
0 ignored issues
show
Coding Style introduced by
As per coding-style, a cast statement should be followed by a single space.
Loading history...
195
                $addCartForm->handleRequest($request);
196 3
197
                if ($addCartForm->isValid()) {
198
                    $addCartData = $addCartForm->getData();
199
200
                    try {
201
                        $this->cartService->addProduct(
0 ignored issues
show
Bug introduced by
The method save cannot be called on $this->cartService->addP...ddCartData['quantity']) (of type boolean).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
202
                            $addCartData['product_class_id'],
203
                            $addCartData['quantity']
204
                        )->save();
205
                    } catch (CartException $e) {
206
                        $app->addRequestError($e->getMessage());
207
                    }
208
209
                    $event = new EventArgs(
210
                        array(
211
                            'form' => $addCartForm,
212
                            'Product' => $Product,
213
                        ),
214
                        $request
215
                    );
216
                    $this->eventDispatcher->dispatch(EccubeEvents::FRONT_PRODUCT_INDEX_COMPLETE, $event);
217
218
                    if ($event->getResponse() !== null) {
219
                        return $event->getResponse();
220
                    }
221
222
                    return $app->redirect($app->url('cart'));
223
                }
224
            }
225
226
            $forms[$Product->getId()] = $addCartForm->createView();
227
        }
228 3
229
        // 表示件数
230
        $builder = $this->formFactory->createNamedBuilder(
231
            'disp_number',
232 3
            ProductListMaxType::class,
233 3
            null,
234 3
            array(
235 3
                'required' => false,
236
                'label' => '表示件数',
237 3
                'allow_extra_fields' => true,
238
            )
239
        );
240
        if ($request->getMethod() === 'GET') {
241
            $builder->setMethod('GET');
242 3
        }
243 3
244
        $event = new EventArgs(
245
            array(
246 3
                'builder' => $builder,
247
            ),
248 3
            $request
249
        );
250 3
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_PRODUCT_INDEX_DISP, $event);
251
252 3
        $dispNumberForm = $builder->getForm();
253
254 3
        $dispNumberForm->handleRequest($request);
255
256 3
        // ソート順
257
        $builder = $this->formFactory->createNamedBuilder(
258
            'orderby',
259 3
            ProductListOrderByType::class,
260 3
            null,
261 3
            array(
262 3
                'required' => false,
263
                'label' => '表示順',
264 3
                'allow_extra_fields' => true,
265
            )
266
        );
267
        if ($request->getMethod() === 'GET') {
268
            $builder->setMethod('GET');
269 3
        }
270 3
271
        $event = new EventArgs(
272
            array(
273 3
                'builder' => $builder,
274
            ),
275 3
            $request
276
        );
277 3
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_PRODUCT_INDEX_ORDER, $event);
278
279 3
        $orderByForm = $builder->getForm();
280
281 3
        $orderByForm->handleRequest($request);
282
283 3
        $Category = $searchForm->get('category_id')->getData();
284
285 3
        return [
286
            'subtitle' => $this->getPageTitle($searchData),
287
            'pagination' => $pagination,
288 3
            'search_form' => $searchForm->createView(),
289 3
            'disp_number_form' => $dispNumberForm->createView(),
290 3
            'order_by_form' => $orderByForm->createView(),
291 3
            'forms' => $forms,
292 3
            'Category' => $Category,
293 3
        ];
294 3
    }
295
296
    /**
0 ignored issues
show
introduced by
Doc comment for parameter "$app" missing
Loading history...
introduced by
Doc comment for parameter "$request" missing
Loading history...
introduced by
Doc comment for parameter "$Product" missing
Loading history...
297
     * 商品詳細画面.
298
     *
299
     * @Method("GET")
300
     * @Route("/products/detail/{id}", name="product_detail", requirements={"id" = "\d+"})
301
     * @Template("Product/detail.twig")
302
     */
0 ignored issues
show
introduced by
Missing @return tag in function comment
Loading history...
303
    public function detail(Application $app, Request $request, Product $Product)
304 4
    {
305
        if (!$this->checkVisibility($Product)) {
306 4
            throw new NotFoundHttpException();
307
        }
308
309 4
        $builder = $this->formFactory->createNamedBuilder(
310
            '',
311 4
            AddCartType::class,
312
            null,
313
            array(
314
                'product' => $Product,
315
                'id_add_product_id' => false,
316
            )
317 4
        );
318
319
        $event = new EventArgs(
320
            array(
321
                'builder' => $builder,
322 4
                'Product' => $Product,
323 4
            ),
324 4
            $request
325 4
        );
326
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_PRODUCT_DETAIL_INITIALIZE, $event);
327 4
328
        $is_favorite = false;
329
        if ($app->isGranted('ROLE_USER')) {
330
            $Customer = $app->user();
331
            $is_favorite = $this->customerFavoriteProductRepository->isFavorite($Customer, $Product);
332 4
        }
333
334 4
        return [
335 4
            'title' => $this->title,
336
            'subtitle' => $Product->getName(),
337 4
            'form' => $builder->getForm()->createView(),
338
            'Product' => $Product,
339 4
            'is_favorite' => $is_favorite,
340
        ];
341
    }
342 4
343
    /**
0 ignored issues
show
introduced by
Doc comment for parameter "$app" missing
Loading history...
introduced by
Doc comment for parameter "$request" missing
Loading history...
introduced by
Doc comment for parameter "$Product" missing
Loading history...
344 4
     * お気に入り追加.
345 3
     *
346
     * @Route("/products/add_favorite/{id}", name="product_add_favorite", requirements={"id" = "\d+"})
347 3
     */
0 ignored issues
show
introduced by
Missing @return tag in function comment
Loading history...
348 2
    public function addFavorite(Application $app, Request $request, Product $Product)
349 2
    {
350 2
        $this->checkVisibility($Product);
351 2
352 2
        $event = new EventArgs(
353 2
            array(
354
                'Product' => $Product,
355 2
            ),
356
            $request
357 2
        );
358 2
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_PRODUCT_FAVORITE_ADD_INITIALIZE, $event);
359
360 2
361
        if ($app->isGranted('ROLE_USER')) {
362 2
            $Customer = $app->user();
363
            $this->customerFavoriteProductRepository->addFavorite($Customer, $Product);
364 2
            $this->session->getFlashBag()->set('product_detail.just_added_favorite', $Product->getId());
365
366
            $event = new EventArgs(
367
                array(
368 2
                    'Product' => $Product,
369
                ),
370
                $request
371
            );
372
            $this->eventDispatcher->dispatch(EccubeEvents::FRONT_PRODUCT_FAVORITE_ADD_COMPLETE, $event);
373
374
            return $app->redirect($app->url('product_detail', array('id' => $Product->getId())));
375 View Code Duplication
        } else {
376
            // 非会員の場合、ログイン画面を表示
377
            //  ログイン後の画面遷移先を設定
378
            $app->setLoginTargetPath($app->url('product_add_favorite', array('id' => $Product->getId())));
379
            $this->session->getFlashBag()->set('eccube.add.favorite', true);
0 ignored issues
show
Documentation introduced by
true is of type boolean, but the function expects a string|array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
380
381
            $event = new EventArgs(
382
                array(
383
                    'Product' => $Product,
384
                ),
385
                $request
386
            );
387
            $this->eventDispatcher->dispatch(EccubeEvents::FRONT_PRODUCT_FAVORITE_ADD_COMPLETE, $event);
388
389
            return $app->redirect($app->url('mypage_login'));
390
        }
391
    }
392
393
    /**
0 ignored issues
show
introduced by
Doc comment for parameter "$app" missing
Loading history...
introduced by
Doc comment for parameter "$request" missing
Loading history...
introduced by
Doc comment for parameter "$Product" missing
Loading history...
394
     * カートに追加.
395
     *
396
     * @Method("POST")
397
     * @Route("/products/add_cart/{id}", name="product_add_cart", requirements={"id" = "\d+"})
398
     */
0 ignored issues
show
introduced by
Missing @return tag in function comment
Loading history...
399
    public function addCart(Application $app, Request $request, Product $Product)
400
    {
401
        if (!$this->checkVisibility($Product)) {
402
            throw new NotFoundHttpException();
403
        }
404
405
        $builder = $this->formFactory->createNamedBuilder(
406
            '',
407
            AddCartType::class,
408
            null,
409
            array(
410
                'product' => $Product,
411
                'id_add_product_id' => false,
412
            )
413
        );
414
415
        $event = new EventArgs(
416
            array(
417
                'builder' => $builder,
418
                'Product' => $Product,
419
            ),
420
            $request
421
        );
422
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_PRODUCT_CART_ADD_INITIALIZE, $event);
423
424
        /* @var $form \Symfony\Component\Form\FormInterface */
425
        $form = $builder->getForm();
426
        $form->handleRequest($request);
427
428
        if (!$form->isValid()) {
429
            throw new NotFoundHttpException();
430
        }
431
432
        $addCartData = $form->getData();
433
434 1
        log_info(
435
            'カート追加処理開始',
436
            array(
437
                'product_id' => $Product->getId(),
438 3
                'product_class_id' => $addCartData['product_class_id'],
439 3
                'quantity' => $addCartData['quantity'],
440
            )
441
        );
442
443
        // カートへ追加
444
        $this->cartService->addProduct($addCartData['product_class_id'], $addCartData['quantity']);
445
446
        // 明細の正規化
447
        $flow = $this->purchaseFlow;
448
        $Cart = $this->cartService->getCart();
449 4
        $result = $flow->calculate($Cart, $app['eccube.purchase.context']());
450 4
451 2
        // 復旧不可のエラーが発生した場合は追加した明細を削除.
452 2
        if ($result->hasError()) {
453
            $this->cartService->removeProduct($addCartData['product_class_id']);
454
            foreach ($result->getErrors() as $error) {
455
                $app->addRequestError($error->getMessage());
456 4
            }
457 4
        }
458 4
459 4
        foreach ($result->getWarning() as $warning) {
460 4
            $app->addRequestError($warning->getMessage());
461
        }
462
463
        $this->cartService->save();
464
465
        log_info(
466
            'カート追加処理完了',
467
            array(
468
                'product_id' => $Product->getId(),
469
                'product_class_id' => $addCartData['product_class_id'],
470 3
                'quantity' => $addCartData['quantity'],
471
            )
472 3
        );
473
474 3
        $event = new EventArgs(
475 1
            array(
476
                'form' => $form,
477 2
                'Product' => $Product,
478
            ),
479
            $request
480
        );
481
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_PRODUCT_CART_ADD_COMPLETE, $event);
482
483
        if ($event->getResponse() !== null) {
484
            return $event->getResponse();
485
        }
486
487
        return $app->redirect($app->url('cart'));
488
489
    }
490
491
    /**
492
     * ページタイトルの設定
493
     *
494
     * @param  null|array $searchData
495
     * @return str
496
     */
497
    private function getPageTitle($searchData)
498
    {
499
        if (isset($searchData['name']) && !empty($searchData['name'])) {
500
            return '検索結果';
501
        } elseif (isset($searchData['category_id']) && $searchData['category_id']) {
502
            return $searchData['category_id']->getName();
503
        } else {
504
            return '全商品';
505
        }
506
    }
507
508
    /**
509
     * 閲覧可能な商品かどうかを判定
510
     * @param Product $Product
511
     * @return boolean 閲覧可能な場合はtrue
512
     */
513
    private function checkVisibility(Product $Product)
514
    {
515
        $is_admin = $this->session->has('_security_admin');
516
517
        // 管理ユーザの場合はステータスやオプションにかかわらず閲覧可能.
518
        if (!$is_admin) {
519
            // 在庫なし商品の非表示オプションが有効な場合.
520
            if ($this->BaseInfo->isNostockHidden()) {
521
                if (!$Product->getStockFind()) {
522
                    return false;
523
                }
524
            }
525
            // 公開ステータスでない商品は表示しない.
526
            if ($Product->getStatus()->getId() !== ProductStatus::DISPLAY_SHOW) {
527
                return false;
528
            }
529
        }
530
        return true;
0 ignored issues
show
introduced by
Missing blank line before return statement
Loading history...
531
    }
532
}
533