Failed Conditions
Pull Request — experimental/3.1 (#2532)
by Kentaro
36:10
created

ProductController   C

Complexity

Total Complexity 37

Size/Duplication

Total Lines 423
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 19

Test Coverage

Coverage 66.3%

Importance

Changes 0
Metric Value
dl 0
loc 423
ccs 120
cts 181
cp 0.663
rs 5.9125
c 0
b 0
f 0
wmc 37
lcom 1
cbo 19

4 Methods

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