Failed Conditions
Pull Request — experimental/3.1 (#2630)
by Kiyotaka
60:01
created

ProductController::addFavorite()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 44
Code Lines 26

Duplication

Lines 16
Ratio 36.36 %

Code Coverage

Tests 12
CRAP Score 2.5

Importance

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