Failed Conditions
Pull Request — experimental/3.1 (#2526)
by Kentaro
49:12 queued 42:52
created

ProductController::detail()   D

Complexity

Conditions 18
Paths 72

Size

Total Lines 159
Code Lines 94

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 287.5388

Importance

Changes 0
Metric Value
cc 18
eloc 94
c 0
b 0
f 0
nc 72
nop 3
dl 0
loc 159
ccs 5
cts 84
cp 0.0595
crap 287.5388
rs 4.7996

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
/*
3
 * 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\Component;
29
use Eccube\Annotation\Inject;
30
use Eccube\Application;
31
use Eccube\Entity\BaseInfo;
32
use Eccube\Common\Constant;
33
use Eccube\Entity\Master\Disp;
34
use Eccube\Entity\Product;
35
use Eccube\Entity\ProductClass;
36
use Eccube\Event\EccubeEvents;
37
use Eccube\Event\EventArgs;
38
use Eccube\Exception\CartException;
39
use Eccube\Form\Type\AddCartType;
40
use Eccube\Form\Type\Master\ProductListMaxType;
41
use Eccube\Form\Type\Master\ProductListOrderByType;
42
use Eccube\Form\Type\SearchProductType;
43
use Eccube\Repository\BaseInfoRepository;
44
use Eccube\Repository\CustomerFavoriteProductRepository;
45
use Eccube\Repository\ProductRepository;
46
use Eccube\Service\CartService;
47
use Eccube\Service\PurchaseFlow\PurchaseFlow;
48
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
49
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
50
use Symfony\Component\EventDispatcher\EventDispatcher;
51
use Symfony\Component\Form\FormFactory;
52
use Symfony\Component\HttpFoundation\Request;
53
use Symfony\Component\HttpFoundation\Session\Session;
54
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
55
56
/**
57
 * @Component
58
 * @Route(service=ProductController::class)
59
 */
60
class ProductController
61
{
62
    /**
63
     * @Inject("eccube.purchase.flow.cart")
64
     * @var PurchaseFlow
65
     */
66
    protected $purchaseFlow;
67
68
    /**
69
     * @Inject("session")
70
     * @var Session
71
     */
72
    protected $session;
73
74
    /**
75
     * @Inject(CustomerFavoriteProductRepository::class)
76
     * @var CustomerFavoriteProductRepository
77
     */
78
    protected $customerFavoriteProductRepository;
79
80
    /**
81
     * @Inject(CartService::class)
82
     * @var CartService
83
     */
84
    protected $cartService;
85
86
    /**
87
     * @Inject(ProductRepository::class)
88
     * @var ProductRepository
89
     */
90
    protected $productRepository;
91
92
    /**
93
     * @Inject("eccube.event.dispatcher")
94
     * @var EventDispatcher
95
     */
96
    protected $eventDispatcher;
97
98
    /**
99
     * @Inject("form.factory")
100
     * @var FormFactory
101
     */
102
    protected $formFactory;
103
104
    /**
105
     * @Inject("orm.em")
106
     * @var EntityManager
107
     */
108
    protected $entityManager;
109
110
    /**
111
     * @Inject(BaseInfo::class)
112
     * @var BaseInfo
113
     */
114
    protected $BaseInfo;
115
116
    private $title;
117
118
    public function __construct()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
119
    {
120
        $this->title = '';
121
    }
122
123
    /**
0 ignored issues
show
introduced by
Doc comment for parameter "$app" missing
Loading history...
introduced by
Doc comment for parameter "$request" missing
Loading history...
124
     * 商品一覧画面.
125
     *
126
     * @Route("/products/list", name="product_list")
127
     * @Template("Product/list.twig")
128
     */
0 ignored issues
show
introduced by
Missing @return tag in function comment
Loading history...
129 3
    public function index(Application $app, Request $request)
130
    {
131
        // Doctrine SQLFilter
132 3
        if ($this->BaseInfo->getNostockHidden() === Constant::ENABLED) {
133
            $this->entityManager->getFilters()->enable('nostock_hidden');
134
        }
135
136
        // handleRequestは空のqueryの場合は無視するため
137 3
        if ($request->getMethod() === 'GET') {
138 3
            $request->query->set('pageno', $request->query->get('pageno', ''));
139
        }
140
141
        // searchForm
142
        /* @var $builder \Symfony\Component\Form\FormBuilderInterface */
143 3
        $builder = $this->formFactory->createNamedBuilder('', SearchProductType::class);
144 3
        $builder->setAttribute('freeze', true);
145 3
        $builder->setAttribute('freeze_display_text', false);
146 3
        if ($request->getMethod() === 'GET') {
147 3
            $builder->setMethod('GET');
148
        }
149
150 3
        $event = new EventArgs(
151
            array(
152 3
                'builder' => $builder,
153
            ),
154 3
            $request
155
        );
156 3
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_PRODUCT_INDEX_INITIALIZE, $event);
157
158
        /* @var $searchForm \Symfony\Component\Form\FormInterface */
159 3
        $searchForm = $builder->getForm();
160
161 3
        $searchForm->handleRequest($request);
162
163
        // paginator
164 3
        $searchData = $searchForm->getData();
165 3
        $qb = $this->productRepository->getQueryBuilderBySearchData($searchData);
166
167 3
        $event = new EventArgs(
168
            array(
169 3
                'searchData' => $searchData,
170 3
                'qb' => $qb,
171
            ),
172 3
            $request
173
        );
174 3
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_PRODUCT_INDEX_SEARCH, $event);
175 3
        $searchData = $event->getArgument('searchData');
176
177 3
        $pagination = $app['paginator']()->paginate(
178 3
            $qb,
179 3
            !empty($searchData['pageno']) ? $searchData['pageno'] : 1,
180 3
            $searchData['disp_number']->getId()
181
        );
182
183
        // addCart form
184 3
        $forms = array();
185 3
        foreach ($pagination as $Product) {
186
            /* @var $builder \Symfony\Component\Form\FormBuilderInterface */
187 3
            $builder = $this->formFactory->createNamedBuilder(
188 3
                '',
189 3
                AddCartType::class,
190 3
                null,
191
                array(
192 3
                    'product' => $Product,
193
                    'allow_extra_fields' => true,
194
                )
195
            );
196 3
            $addCartForm = $builder->getForm();
197
198 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...
199
                $addCartForm->handleRequest($request);
200
201
                if ($addCartForm->isValid()) {
202
                    $addCartData = $addCartForm->getData();
203
204
                    try {
205
                        $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...
206
                            $addCartData['product_class_id'],
207
                            $addCartData['quantity']
208
                        )->save();
209
                    } catch (CartException $e) {
210
                        $app->addRequestError($e->getMessage());
211
                    }
212
213
                    $event = new EventArgs(
214
                        array(
215
                            'form' => $addCartForm,
216
                            'Product' => $Product,
217
                        ),
218
                        $request
219
                    );
220
                    $this->eventDispatcher->dispatch(EccubeEvents::FRONT_PRODUCT_INDEX_COMPLETE, $event);
221
222
                    if ($event->getResponse() !== null) {
223
                        return $event->getResponse();
224
                    }
225
226
                    return $app->redirect($app->url('cart'));
227
                }
228
            }
229
230 3
            $forms[$Product->getId()] = $addCartForm->createView();
231
        }
232
233
        // 表示件数
234 3
        $builder = $this->formFactory->createNamedBuilder(
235 3
            'disp_number',
236 3
            ProductListMaxType::class,
237 3
            null,
238
            array(
239 3
                'required' => false,
240
                'label' => '表示件数',
241
                'allow_extra_fields' => true,
242
            )
243
        );
244 3
        if ($request->getMethod() === 'GET') {
245 3
            $builder->setMethod('GET');
246
        }
247
248 3
        $event = new EventArgs(
249
            array(
250 3
                'builder' => $builder,
251
            ),
252 3
            $request
253
        );
254 3
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_PRODUCT_INDEX_DISP, $event);
255
256 3
        $dispNumberForm = $builder->getForm();
257
258 3
        $dispNumberForm->handleRequest($request);
259
260
        // ソート順
261 3
        $builder = $this->formFactory->createNamedBuilder(
262 3
            'orderby',
263 3
            ProductListOrderByType::class,
264 3
            null,
265
            array(
266 3
                'required' => false,
267
                'label' => '表示順',
268
                'allow_extra_fields' => true,
269
            )
270
        );
271 3
        if ($request->getMethod() === 'GET') {
272 3
            $builder->setMethod('GET');
273
        }
274
275 3
        $event = new EventArgs(
276
            array(
277 3
                'builder' => $builder,
278
            ),
279 3
            $request
280
        );
281 3
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_PRODUCT_INDEX_ORDER, $event);
282
283 3
        $orderByForm = $builder->getForm();
284
285 3
        $orderByForm->handleRequest($request);
286
287 3
        $Category = $searchForm->get('category_id')->getData();
288
289
        return [
290 3
            'subtitle' => $this->getPageTitle($searchData),
291 3
            'pagination' => $pagination,
292 3
            'search_form' => $searchForm->createView(),
293 3
            'disp_number_form' => $dispNumberForm->createView(),
294 3
            'order_by_form' => $orderByForm->createView(),
295 3
            'forms' => $forms,
296 3
            'Category' => $Category,
297
        ];
298
    }
299
300
    /**
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...
301
     * 商品詳細画面.
302
     *
303
     * @Route("/products/detail/{id}", name="product_detail", requirements={"id" = "\d+"})
304
     * @Template("Product/detail.twig")
305
     */
0 ignored issues
show
introduced by
Missing @return tag in function comment
Loading history...
306 4
    public function detail(Application $app, Request $request, Product $Product)
307
    {
308 4
        $is_admin = $request->getSession()->has('_security_admin');
309
310
        // 管理ユーザの場合はステータスやオプションにかかわらず閲覧可能.
311 4
        if (!$is_admin) {
312
            // 在庫なし商品の非表示オプションが有効な場合.
313 4
            if ($this->BaseInfo->getNostockHidden()) {
314
                if (!$Product->getStockFind()) {
315
                    throw new NotFoundHttpException();
316
                }
317
            }
318
            // 公開ステータスでない商品は表示しない.
319 4
            if ($Product->getStatus()->getId() !== Disp::DISPLAY_SHOW) {
320
                throw new NotFoundHttpException();
321
            }
322
        }
323
324
        $builder = $this->formFactory->createNamedBuilder(
325
            '',
326
            AddCartType::class,
327
            null,
328
            array(
329
                'product' => $Product,
330
                'id_add_product_id' => false,
331
            )
332
        );
333
334
        $event = new EventArgs(
335
            array(
336
                'builder' => $builder,
337
                'Product' => $Product,
338
            ),
339
            $request
340
        );
341
        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_PRODUCT_DETAIL_INITIALIZE, $event);
342
343
        /* @var $form \Symfony\Component\Form\FormInterface */
344
        $form = $builder->getForm();
345
346
        if ($request->getMethod() === 'POST') {
347
            $form->handleRequest($request);
348
349
            if ($form->isValid()) {
350
                $addCartData = $form->getData();
351
                if ($addCartData['mode'] === 'add_favorite') {
352
                    if ($app->isGranted('ROLE_USER')) {
353
                        $Customer = $app->user();
354
                        $this->customerFavoriteProductRepository->addFavorite($Customer, $Product);
355
                        $this->session->getFlashBag()->set('product_detail.just_added_favorite', $Product->getId());
356
357
                        $event = new EventArgs(
358
                            array(
359
                                'form' => $form,
360
                                'Product' => $Product,
361
                            ),
362
                            $request
363
                        );
364
                        $this->eventDispatcher->dispatch(EccubeEvents::FRONT_PRODUCT_DETAIL_FAVORITE, $event);
365
366
                        if ($event->getResponse() !== null) {
367
                            return $event->getResponse();
368
                        }
369
370
                        return $app->redirect($app->url('product_detail', array('id' => $Product->getId())));
371
                    } else {
372
                        // 非会員の場合、ログイン画面を表示
373
                        //  ログイン後の画面遷移先を設定
374
                        $app->setLoginTargetPath($app->url('product_detail', array('id' => $Product->getId())));
375
                        $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...
376
377
                        return $app->redirect($app->url('mypage_login'));
378
                    }
379
                } elseif ($addCartData['mode'] === 'add_cart') {
0 ignored issues
show
Coding Style introduced by
Blank line found at start of control structure
Loading history...
380
381
                    log_info(
382
                        'カート追加処理開始',
383
                        array(
384
                            'product_id' => $Product->getId(),
385
                            'product_class_id' => $addCartData['product_class_id'],
386
                            'quantity' => $addCartData['quantity'],
387
                        )
388
                    );
389
390
                    // カートを取得
391
                    $Cart = $this->cartService->getCart();
392
393
                    // カートへ追加
394
                    $this->cartService->addProduct($addCartData['product_class_id'], $addCartData['quantity']);
395
396
                    // 明細の正規化
397
                    $flow = $this->purchaseFlow;
398
                    $result = $flow->calculate($Cart, $app['eccube.purchase.context']());
399
400
                    // 復旧不可のエラーが発生した場合は追加した明細を削除.
401
                    if ($result->hasError()) {
402
                        $Cart->removeCartItemByIdentifier(ProductClass::class, $addCartData['product_class_id']);
403
                        foreach ($result->getErrors() as $error) {
404
                            $app->addRequestError($error->getMessage());
405
                        }
406
                    }
407
408
                    foreach ($result->getWarning() as $warning) {
409
                        $app->addRequestError($warning->getMessage());
410
                    }
411
412
                    $this->cartService->save();
413
414
                    log_info(
415
                        'カート追加処理完了',
416
                        array(
417
                            'product_id' => $Product->getId(),
418
                            'product_class_id' => $addCartData['product_class_id'],
419
                            'quantity' => $addCartData['quantity'],
420
                        )
421
                    );
422
423
                    $event = new EventArgs(
424
                        array(
425
                            'form' => $form,
426
                            'Product' => $Product,
427
                        ),
428
                        $request
429
                    );
430
                    $this->eventDispatcher->dispatch(EccubeEvents::FRONT_PRODUCT_DETAIL_COMPLETE, $event);
431
432
                    if ($event->getResponse() !== null) {
433
                        return $event->getResponse();
434
                    }
435
436
                    return $app->redirect($app->url('cart'));
437
                }
438
            }
439
        } else {
440
            $addFavorite = $this->session->getFlashBag()->get('eccube.add.favorite');
441
            if (!empty($addFavorite)) {
442
                // お気に入り登録時にログインされていない場合、ログイン後にお気に入り追加処理を行う
443
                if ($app->isGranted('ROLE_USER')) {
444
                    $Customer = $app->user();
445
                    $this->customerFavoriteProductRepository->addFavorite($Customer, $Product);
446
                    $this->session->getFlashBag()->set('product_detail.just_added_favorite', $Product->getId());
447
                }
448
            }
449
        }
450
451
        $is_favorite = false;
452
        if ($app->isGranted('ROLE_USER')) {
453
            $Customer = $app->user();
454
            $is_favorite = $this->customerFavoriteProductRepository->isFavorite($Customer, $Product);
455
        }
456
457
        return [
458
            'title' => $this->title,
459
            'subtitle' => $Product->getName(),
460
            'form' => $form->createView(),
461
            'Product' => $Product,
462
            'is_favorite' => $is_favorite,
463
        ];
464
    }
465
466
    /**
467
     * ページタイトルの設定
468
     *
469
     * @param  null|array $searchData
470
     * @return str
471
     */
472 3
    private function getPageTitle($searchData)
473
    {
474 3
        if (isset($searchData['name']) && !empty($searchData['name'])) {
475
            return '検索結果';
476 3
        } elseif (isset($searchData['category_id']) && $searchData['category_id']) {
477 1
            return $searchData['category_id']->getName();
478
        } else {
479 2
            return '全商品';
480
        }
481
    }
482
}
483